irtimmer/tpm2-pk11

Core dump (corrupted double-linked list) in p11tool occurs only when no tpm2-pk11 log file specified

Opened this issue ยท 4 comments

Thanks for your work on this project ๐Ÿ‘

Noticed a small (and strange) bug. When no log file is specified in the tpm2-pk11 config file, there is a core dump upon attempting to list the available certificates from p11tool. I have isolated the issue to the log key within the config file being absent.

Initial config file:

# Type can be device/socket/tabrmd
type device
# Hostname to connect when using socket
hostname localhost
# Port number of TPM socket to connect to
port 2321
# Device to use as TPM
device /dev/tpmrm0
# Sign using encrypt in case TPM doesn't support hash format
# For example SSH use SHA512 which isn't supported by all TPM's
# Enabling this option requires key's to be encryption keys instead of signing only keys
sign-using-encrypt false
certificates ~/.tpm2/certs

Attempting to list certificates (one is created, present, and working in Firefox per wiki instructions) results in:

p11tool --list-certs pkcs11:model=TPM2
Object 0:
	URL: pkcs11:model=TPM2;manufacturer=NTC;serial=123456789;token=;id=%0[....];object=000B[....];type=cert
	Type: X.509 Certificate
	Label: [....]
	Flags: CKA_WRAP/UNWRAP; CKA_PRIVATE; CKA_ALWAYS_AUTH; CKA_TRUSTED; CKA_EXTRACTABLE; CKA_NEVER_EXTRACTABLE; CKA_SENSITIVE; 
	ID: 00:0b:[....]

corrupted double-linked list
[1]    4766 abort (core dumped)  p11tool --list-certs pkcs11:model=TPM2

If a log file is defined (by adding the below to the config file):

log ~/.tpm2/logfile.txt

then there is no corrupted double-linked list, and no resulting core dump. I can reproduce this by removing and adding the above line from the config as required.

Additionally, in testing, I found the log parameter requires an absolute path (i.e. cannot accept ~/.tpm2/log.txt), otherwise no output is created.

The log file path that started with ~, for example:

log ~/.tpm2/logfile.txt

is not yet supported.

I'm hitting this issue even with a logfile provided. For what it's worth, firefox also crashes when loading the module.

sgtio commented

I'm having a similar issue, but I'm not sure if I'm experiencing the same bug. The output from p11tool is:

*** Error in '/usr/bin/p11tool': free(): invalid pointer: 0x76c1c884 ***

I have compiled the library with debug symbols and run it through gdb:

The crash occurs when the library tries to free the session->objects->object->userdata list when closing a session with C_CloseSession

Breakpoint 2, object_free (list=0x76c1c894 <main_arena+256>) at /home/pi/tpm2-pk11/src/objects.c:81
81        while (list != NULL) {

(gdb) bt
#0  object_free (list=0x76c1c894 <main_arena+256>) at /home/pi/tpm2-pk11/src/objects.c:81
#1  0x7698cdc0 in session_close (session=0x8cfa8) at /home/pi/tpm2-pk11/src/sessions.c:152
#2  0x7698a97c in C_CloseSession (session_handle=577448) at /home/pi/tpm2-pk11/src/pk11.c:87
#3  0x76dbc83c in ?? () from /usr/lib/arm-linux-gnueabihf/libp11-kit.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) f 1
#1  0x7698cdc0 in session_close (session=0x8cfa8) at /home/pi/tpm2-pk11/src/sessions.c:152
152       object_free(session->objects);
(gdb) p session->objects->object->userdata
$30 = (void *) 0x76c1c884 <main_arena+240>

It seems like the session that p11tool is trying to close was created erroneously. Below is the flow of session_init for the session that is later closed.

session_init (session=0x8cfa8, config=0x769a136c <pk11_config>) at /home/pi/tpm2-pk11/src/sessions.c:40
40        session->context = NULL;
(gdb) n
42        size_t size = 0;
(gdb) n
43        TSS2_TCTI_CONTEXT *tcti_ctx = NULL;
(gdb) n
50        switch(config->type) {
(gdb) n
63            rc = Tss2_Tcti_Device_Init(NULL, &size, device_conf);
(gdb) n
64            break;
(gdb) n
76        if (rc != TSS2_RC_SUCCESS)
(gdb) print rc
$25 = 0
(gdb) n
79        tcti_ctx = (TSS2_TCTI_CONTEXT*) calloc(1, size);
(gdb) n
80        if (tcti_ctx == NULL)
(gdb) n
90        switch(config->type) {
(gdb) n
105           TSS_COMPAT_DEVICE_CONF(device_conf, config->device != NULL ? config->device : DEFAULT_DEVICE);
(gdb) n
106           rc = Tss2_Tcti_Device_Init(tcti_ctx, &size, device_conf);
(gdb) n
107           break;
(gdb) n
120       if (rc != TSS2_RC_SUCCESS)
(gdb) n
121         goto cleanup;
(gdb) p rc
$26 = 655370

As you can see here, the session_init function does not reach the point where session->objects list is populated. Therefore, the value in that position of the struct is garbage after session_init. Which means that when we try to free that session, we will crash trying to free session->objects. I have created a pull request that zeroes the memory allocated for a session before calling session_init (6df6fa1).

I also noticed that when we fail to initialize the session, we don't free the allocated memory, but I'm not sure if that is correct or not.

The funny thing here is that the library reports the error to the upper layer (i.e. returns CKR_GENERAL_ERROR) but it seems like p11tool doesn't care and tells us to free the session anyway. Again, not sure if that is expected behavior or not.

Anyway, I hope this helps, and I can provide more information regarding this if needed.

EDIT: Forgot to add the last line of the long comment.

rc: 655370 == 0xA000A
TSS2_TCTI_RC_IO_ERROR 0xA000A was defined in https://github.com/tpm2-software/tpm2-tss/blob/master/include/tss2/tss2_common.h

  • tpm2_rc_decode 0xA000A
error layer
  hex: 0xa0000
  identifier: TSS2_TCTI_ERROR_LEVEL
  description: Error from the TCTI
base error code
  identifier: TSS2_BASE_RC_IO_ERROR
  description: IO failure