From 426cc786c64200d01d595bd9675771091fb142fd Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Mon, 9 Mar 2026 13:13:39 -0400 Subject: [PATCH] tpm2: Only write the necessary number of bytes of command bitmaps Only write the necessary number of bytes of the ppList and auditCommands bitmaps. The entries in both of these bitmaps are set by a command's index and the necessary number of bytes can be determined by finding the command with the highest command code that is enabled in the current profile (1). This in turn can be found by by searching for the last byte in the enableCommandsByIdx bitmap that has any bit set. 1) It would be possible to skip writing these arrays entirely if they have no bits set. The unmarshalling functions would clear the arrays. Signed-off-by: Stefan Berger --- src/tpm2/NVMarshal.c | 19 +++++++++++++------ src/tpm2/RuntimeCommands.c | 22 ++++++++++++++++++++++ src/tpm2/RuntimeCommands_fp.h | 3 +++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index fef13a19..7c14bb02 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -4106,7 +4106,8 @@ skip_future_versions: static UINT16 PERSISTENT_DATA_PPList_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, - UINT16 blob_version, UINT32 commandCount) + UINT16 blob_version, + UINT32 commandCount, UINT32 commandArraySize) { UINT8 ppList[(110 + 7) / 8]; UINT16 array_size; @@ -4126,7 +4127,8 @@ PERSISTENT_DATA_PPList_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size ptr = ppList; } else { /* write the array as it is */ - array_size = sizeof(data->ppList); + array_size = commandArraySize; + assert(array_size <= sizeof(data->ppList)); ptr = data->ppList; } written = UINT16_Marshal(&array_size, buffer, size); @@ -4171,7 +4173,8 @@ PERSISTENT_DATA_PPList_Unmarshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *si static UINT16 PERSISTENT_DATA_AuditCommands_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, - UINT16 blob_version, UINT32 commandCount) + UINT16 blob_version, + UINT32 commandCount, UINT32 commandArraySize) { UINT8 auditCommands[(110 + 1 + 7) / 8]; UINT16 array_size; @@ -4192,7 +4195,8 @@ PERSISTENT_DATA_AuditCommands_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT3 ptr = auditCommands; } else { /* write the array as it is */ - array_size = sizeof(data->auditCommands); + array_size = commandArraySize; + assert(array_size <= sizeof(data->auditCommands)); ptr = data->auditCommands; } written = UINT16_Marshal(&array_size, buffer, size); @@ -4244,6 +4248,7 @@ PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, struct RuntimeProfile *RuntimeProfile) { UINT32 commandCount = RuntimeCommandsCountEnabled(&RuntimeProfile->RuntimeCommands); + UINT32 commandArraySize = RuntimeCommandsGetArraySize(&RuntimeProfile->RuntimeCommands); UINT16 written; UINT8 clocksize; BOOL has_block; @@ -4299,7 +4304,8 @@ PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, written += TPML_PCR_SELECTION_Marshal(&data->pcrAllocated, buffer, size); - written += PERSISTENT_DATA_PPList_Marshal(data, buffer, size, blob_version, commandCount); + written += PERSISTENT_DATA_PPList_Marshal(data, buffer, size, blob_version, + commandCount, commandArraySize); written += UINT32_Marshal(&data->failedTries, buffer, size); written += UINT32_Marshal(&data->maxTries, buffer, size); written += UINT32_Marshal(&data->recoveryTime, buffer, size); @@ -4307,7 +4313,8 @@ PERSISTENT_DATA_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, written += BOOL_Marshal(&data->lockOutAuthEnabled, buffer, size); written += UINT16_Marshal(&data->orderlyState, buffer, size); - written += PERSISTENT_DATA_AuditCommands_Marshal(data, buffer, size, blob_version, commandCount); + written += PERSISTENT_DATA_AuditCommands_Marshal(data, buffer, size, blob_version, + commandCount, commandArraySize); written += TPM_ALG_ID_Marshal(&data->auditHashAlg, buffer, size); written += UINT64_Marshal(&data->auditCounter, buffer, size); written += UINT32_Marshal(&data->algorithmSet, buffer, size); diff --git a/src/tpm2/RuntimeCommands.c b/src/tpm2/RuntimeCommands.c index 7756104a..3edd31f5 100644 --- a/src/tpm2/RuntimeCommands.c +++ b/src/tpm2/RuntimeCommands.c @@ -476,6 +476,28 @@ RuntimeCommandPrint(char *buffer, return nbuffer; } +/* + * Determine the size of a byte array where each bit represents a command. + * The size of the array depends on the command with the highest command code + * that is enabled. This function can be used to determine how many bytes + * of the ppList and auditCommands bitmaps are used at maximum and need to be + * written. + */ +LIB_EXPORT size_t +RuntimeCommandsGetArraySize(struct RuntimeCommands *RuntimeCommands) +{ + size_t i; + + /* search for byte where command with highest code is enabled */ + for (i = sizeof(RuntimeCommands->enabledCommandsByIdx) - 1; + i >= 0; + i--) { + if (RuntimeCommands->enabledCommandsByIdx[i]) + return i + 1; + } + return 0; +} + LIB_EXPORT char * RuntimeCommandsPrint(struct RuntimeCommands *RuntimeCommands, enum RuntimeCommandType rct) diff --git a/src/tpm2/RuntimeCommands_fp.h b/src/tpm2/RuntimeCommands_fp.h index f2a67d3b..8ed19a75 100644 --- a/src/tpm2/RuntimeCommands_fp.h +++ b/src/tpm2/RuntimeCommands_fp.h @@ -80,6 +80,9 @@ RuntimeCommandsCheckEnabled(struct RuntimeCommands *RuntimeCommands, TPM_CC cc // IN: the command code to check ); +size_t +RuntimeCommandsGetArraySize(struct RuntimeCommands *RuntimeCommands); + LIB_EXPORT UINT32 RuntimeCommandsCountEnabled(struct RuntimeCommands *RuntimeCommands);