Skip to content

C_DestroyObject ignoring tpm_handle, possible transient leak. #900

@JakubPospiech

Description

@JakubPospiech

Hello,

I have stumpled on some interesting, maybe unintended relation between transient objects and C_DestroyObject() .

I have a test, that essentially does following chain of calls (I cannot provide original code)

C_GenerateKeyPair(session, ...);
C_DestroyObject(session, pubHandle); // Destroy pubKey
C_DestroyObject(session, privHandle); // Destroy privKey

Test is passing, keys are generated, and destroyed right after, however after running this test few times in a row "out of memory for session contexts" error started to appear.

Running tpm2 tpm2_getcap properties-variable before and after the test is showing that after each test run TPM2_PT_HR_TRANSIENT_AVAIL is reduced by 2.

During investigation, I modified this test case calls to:

C_GenerateKeyPair(session, ...);
C_Logout(session);
C_CloseSession(session);

C_OpenSession(..., &session);
C_Login(session, ...);
C_DestroyObject(session, pubHandle); // Destroy pubKey
C_DestroyObject(session, privHandle); // Destroy privKey

This time test was also passing, but TPM2_PT_HR_TRANSIENT_AVAIL was no longer reduced by each call, so test could be performed over and over.

Checking source code I found that during C_Logout() all handles are evicted:

    /*
     * For each object:
     *   - Evict the TPM Handles
     *   - Cleanse CKA_VALUE fields for private values.
     */
    if (tok->tobjects.head) {

        list *cur = &tok->tobjects.head->l;
        while(cur) {
            tobject *tobj = list_entry(cur, tobject, l);
            cur = cur->next;

            /* if it's CKA_PRIVATE == CK_TRUE and it has a CKA_VALUE field, clear it */
            CK_BBOOL cka_private = attr_list_get_CKA_PRIVATE(tobj->attrs, CK_FALSE);
            CK_ATTRIBUTE_PTR a = attr_get_attribute_by_type(tobj->attrs, CKA_VALUE);
            if (cka_private && a && a->pValue && a->ulValueLen) {
                attr_pfree_cleanse(a);
            }

            if (tobj->tpm_handle) {
                bool result = tpm_flushcontext(tpm, tobj->tpm_handle);
                assert(result);
                UNUSED(result);
                tobj->tpm_handle = 0;

                /* Clear the unwrapped auth value for tertiary objects */
                twist_free(tobj->unsealed_auth);
                tobj->unsealed_auth = NULL;
            }
        }
    }

However, C_DestroyObject() only removes object but does not evict tpm_handle, as a result by removing tobj it deletes a reference to TPM handle thus if handle exists it is no longer accesible after that and it cannot be evicted during C_Logout().

Is it intended behaviour? At a first glance it looks like a memory leak to me, do I misunderstand something?

I am using tpm2-pkcs11 1.9.1, without abrmd.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions