tpm2-tss
tpm2-tss copied to clipboard
Memory leak in error path of Esys_Initialize
Esys_Initialize
initializes the TCTI:
https://github.com/tpm2-software/tpm2-tss/blob/9f336a5064a0295608ca0e7a4d70c4db18664a37/src/tss2-esys/esys_context.c#L71-L75
The function Tss2_TctiLdr_Initialize
(via Tss2_TctiLdr_Initialize_Ex
) allocates memory that is not implicitly freed on failure:
https://github.com/tpm2-software/tpm2-tss/blob/9f336a5064a0295608ca0e7a4d70c4db18664a37/src/tss2-tcti/tctildr.c#L521-L528
When Tss2_TctiLdr_Initialize
returns after a failure, the cleanup_return
in Esys_Initialize
is then executed:
https://github.com/tpm2-software/tpm2-tss/blob/9f336a5064a0295608ca0e7a4d70c4db18664a37/src/tss2-esys/esys_context.c#L95-L98
However, after the execution of Tss2_Tcti_Finalize
there is a missing call to free
unlike what is done in the error path of Tss2_TctiLdr_Initialize_Ex
:
https://github.com/tpm2-software/tpm2-tss/blob/9f336a5064a0295608ca0e7a4d70c4db18664a37/src/tss2-tcti/tctildr.c#L530-L535
@polarina In the cleanup_return
part of Esys_Initialize``Tss2_TctiLdr_Finalize
is called. This function calls tctildr_finalize
where the tcti context is freed. So there is no leak, is there?
@polarina In the
cleanup_return
part ofEsys_Initialize
Tss2_TctiLdr_Finalize `` is called. This function callstctildr_finalize
where the tcti context is freed. So there is no leak, is there?
There is. There is no call to free
on tctiContext
.
Here is a reproducer:
#include <tss2/tss2_esys.h>
int main(void) {
ESYS_CONTEXT *ctx = NULL;
TSS2_RC rc = Esys_Initialize(&ctx, NULL, NULL);
if (rc) {
return 1;
}
Esys_Finalize(&ctx);
return 0;
}
Compile with gcc esys-leak.c -l tss2-esys -o esys-leak
and run via Valgrind, valgrind --leak-check=full -s ./esys-leak
, as an unprivileged user who does not have access to the TPM:
==1309605==
==1309605== HEAP SUMMARY:
==1309605== in use at exit: 96 bytes in 1 blocks
==1309605== total heap usage: 103 allocs, 102 frees, 56,932 bytes allocated
==1309605==
==1309605== 96 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1309605== at 0x484A0FC: calloc (vg_replace_malloc.c:1675)
==1309605== by 0x48E810E: UnknownInlinedFun (tctildr.c:520)
==1309605== by 0x48E810E: UnknownInlinedFun (tctildr.c:551)
==1309605== by 0x48E810E: Esys_Initialize (esys_context.c:70)
==1309605== by 0x40115B: main (in /home/gabriel/rusl/esys-leak)
==1309605==
==1309605== LEAK SUMMARY:
==1309605== definitely lost: 96 bytes in 1 blocks
==1309605== indirectly lost: 0 bytes in 0 blocks
==1309605== possibly lost: 0 bytes in 0 blocks
==1309605== still reachable: 0 bytes in 0 blocks
==1309605== suppressed: 0 bytes in 0 blocks
==1309605==
==1309605== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
LeakSanitizer also picks up the leak:
=================================================================
==1309536==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 96 byte(s) in 1 object(s) allocated from:
#0 0x7f820e0f6270 in calloc (/lib64/libasan.so.8+0xf6270) (BuildId: 6ac482fdae6aad7cf603c8e6ab3042fb9d4725af)
#1 0x7f820e89310e in Esys_Initialize (/lib64/libtss2-esys.so.0+0x6810e) (BuildId: 901c827f0bb06673b2cdd265db2e59474ed57294)
#2 0x401222 in main (/home/gabriel/rusl/esys-leak+0x401222) (BuildId: b88db0d10e252a64478a432c120c6c5f8c9b8d16)
#3 0x7f820de3d087 in __libc_start_call_main (/lib64/libc.so.6+0x2a087) (BuildId: b098f1c75a76548bb230d8f551eae07a2aeccf06)
#4 0x7f820de3d14a in __libc_start_main_alias_2 (/lib64/libc.so.6+0x2a14a) (BuildId: b098f1c75a76548bb230d8f551eae07a2aeccf06)
#5 0x4010b4 in _start (/home/gabriel/rusl/esys-leak+0x4010b4) (BuildId: b88db0d10e252a64478a432c120c6c5f8c9b8d16)
SUMMARY: AddressSanitizer: 96 byte(s) leaked in 1 allocation(s).
@polarina Thank you for the example. I will create a PR.