From 45c2d9667d670b88315394f6c4c2c4a17719b6c5 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 5 Mar 2026 10:15:19 -0500 Subject: [PATCH 1/3] tpm2: Limit array_size to current size of array (ppList/auditCommands) (BUGFIX) The current libtpms v0.10.2 does not accept a TPM 2 state that was written with a more recent version of libtpms if the sizes of ppList and/or auditCommands increased. Remove the asserts that trigger state reading failures and limit array_size to the sizeof(data->ppList) and sizeof(data->auditCommands) respectively . More recent versions of libtpms, if they support more TPM 2 commands, will extend these arrays but those new commands will not be usable by older versions of libtpms (via profile and StateFormatLevel) and can therefore be ignored by truncating those arrays. Signed-off-by: Stefan Berger --- src/tpm2/NVMarshal.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index 1a275e536..f8072c70b 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -4136,8 +4136,11 @@ PERSISTENT_DATA_PPList_Unmarshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *si rc = ConvertFromCompressedBitArray(buf, array_size, data->ppList, sizeof(data->ppList)); } else { + /* later versions of libtpms may write bigger arrays - truncate them */ + if (array_size > sizeof(data->ppList)) + array_size = sizeof(data->ppList); + memset(data->ppList, 0, sizeof(data->ppList)); - assert(array_size <= sizeof(data->ppList)); memcpy(data->ppList, buf, array_size); } } @@ -4199,8 +4202,11 @@ PERSISTENT_DATA_AuditCommands_Unmarshal(PERSISTENT_DATA *data, BYTE **buffer, IN rc = ConvertFromCompressedBitArray(buf, array_size, data->auditCommands, sizeof(data->auditCommands)); } else { + /* later versions of libtpms may write bigger arrays - truncate them */ + if (array_size > sizeof(data->auditCommands)) + array_size = sizeof(data->auditCommands); + memset(data->auditCommands, 0, sizeof(data->auditCommands)); - assert(array_size <= sizeof(data->auditCommands)); memcpy(data->auditCommands, buf, array_size); } } From a620c161bf1fb1ab9f84bde230367739b64733d3 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 5 Mar 2026 09:15:16 -0500 Subject: [PATCH 2/3] tpm2: Use BITS_TO_BYTES in NVMarshal.c for calculating array sizes Use the BITS_TO_BYTES macro where the number of bits is used for calculating the size of a byte array. Also, make the clearing of the rest of the byte arrays (ppList and auditCommands) a bit more efficient than clearing the whole array before copying the new data into it. Signed-off-by: Stefan Berger --- src/tpm2/NVMarshal.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/tpm2/NVMarshal.c b/src/tpm2/NVMarshal.c index f8072c70b..512f19df6 100644 --- a/src/tpm2/NVMarshal.c +++ b/src/tpm2/NVMarshal.c @@ -4087,7 +4087,7 @@ static UINT16 PERSISTENT_DATA_PPList_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, UINT16 blob_version, UINT32 commandCount) { - UINT8 ppList[(110 + 7) / 8]; + UINT8 ppList[BITS_TO_BYTES(110)]; UINT16 array_size; UINT16 written; UINT8 *ptr; @@ -4140,8 +4140,11 @@ PERSISTENT_DATA_PPList_Unmarshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *si if (array_size > sizeof(data->ppList)) array_size = sizeof(data->ppList); - memset(data->ppList, 0, sizeof(data->ppList)); memcpy(data->ppList, buf, array_size); + /* clear the rest of byte array */ + MUST_BE(sizeof(data->ppList[0]) == sizeof(BYTE)); + while (array_size < ARRAY_SIZE(data->ppList)) + data->ppList[array_size++] = 0; } } } @@ -4152,7 +4155,7 @@ static UINT16 PERSISTENT_DATA_AuditCommands_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT32 *size, UINT16 blob_version, UINT32 commandCount) { - UINT8 auditCommands[(110 + 1 + 7) / 8]; + UINT8 auditCommands[BITS_TO_BYTES(110 + 1)]; UINT16 array_size; UINT16 written; UINT8 *ptr; @@ -4164,7 +4167,7 @@ PERSISTENT_DATA_AuditCommands_Marshal(PERSISTENT_DATA *data, BYTE **buffer, INT3 * was using a COMPRESSED_LIST. */ assert(commandCount <= 110); - array_size = ((commandCount + 1) + 7) / 8; /* same as in Global.h PERSISTENT_DATA */ + array_size = BITS_TO_BYTES(commandCount + 1); /* same as in Global.h PERSISTENT_DATA */ assert(sizeof(auditCommands) >= array_size); ConvertToCompressedBitArray(data->auditCommands, sizeof(data->auditCommands), auditCommands, array_size); @@ -4206,8 +4209,11 @@ PERSISTENT_DATA_AuditCommands_Unmarshal(PERSISTENT_DATA *data, BYTE **buffer, IN if (array_size > sizeof(data->auditCommands)) array_size = sizeof(data->auditCommands); - memset(data->auditCommands, 0, sizeof(data->auditCommands)); memcpy(data->auditCommands, buf, array_size); + /* clear the rest of byte array */ + MUST_BE(sizeof(data->auditCommands[0]) == sizeof(BYTE)); + while (array_size < ARRAY_SIZE(data->auditCommands)) + data->auditCommands[array_size++] = 0; } } } From 636af2caa8d46b6e0ed3e8cae24ef7145f5729ee Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Thu, 5 Mar 2026 09:35:32 -0500 Subject: [PATCH 3/3] tests: Remove checks for sizes of ppList and auditCommands It is not necessary anymore to check for an increase of the sizes of the PERSISTENT_DATA ppList and auditCommands fields since they are marshalled with an array-size indicator. Any previous version of libtpms should be able to resume a profile with the ppList and auditCommands written with a later version. If later versions have new commands, then those new commands must be added beyond the current TPM_CC_FIRST. The ppList and auditCommands may be bigger than before but can be truncated IFF new commands were added. These new commands will not be usable with the older verison of libtpms based on the StateFormatLevel then. Signed-off-by: Stefan Berger --- src/tpm2/RuntimeCommands.c | 2 ++ tests/nvram_offsets.c | 24 ------------------------ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/src/tpm2/RuntimeCommands.c b/src/tpm2/RuntimeCommands.c index be8e30e2d..7a61049ef 100644 --- a/src/tpm2/RuntimeCommands.c +++ b/src/tpm2/RuntimeCommands.c @@ -413,6 +413,8 @@ RuntimeCommandsCountEnabled(struct RuntimeCommands *RuntimeCommands) TPM_CC commandCode; UINT32 count = 0; + /* the following assert must never change */ + MUST_BE(TPM_CC_FIRST == TPM_CC_NV_UndefineSpaceSpecial); for (commandCode = TPM_CC_FIRST; commandCode < sizeof(RuntimeCommands->enabledCommands) * 8; commandCode++) { diff --git a/tests/nvram_offsets.c b/tests/nvram_offsets.c index 24311eec3..92e9ad430 100644 --- a/tests/nvram_offsets.c +++ b/tests/nvram_offsets.c @@ -8,30 +8,6 @@ extern BYTE s_indexOrderlyRam[RAM_INDEX_SPACE]; int main(void) { - PERSISTENT_DATA pd; - - /* Check size of ppList that expands with new commands */ - /* was 14 when COMPRESSED_LISTS was enabled */ -#define PD_PP_LIST_EXP_SIZE 17 - if (sizeof(pd.ppList) != PD_PP_LIST_EXP_SIZE) { - fprintf(stderr, - "sizeof(PERSISTENT_DATA.ppList) does not have expected size " - "of %u bytes but %zu bytes\n", - PD_PP_LIST_EXP_SIZE, sizeof(pd.ppList)); - return EXIT_FAILURE; - } - - /* Check size of auditCommands that expands with new commands */ - /* was 14 when COMPRESSED_LISTS was enabled */ -#define PD_AUDIT_COMMANDS_EXP_SIZE 17 - if (sizeof(pd.auditCommands) != PD_AUDIT_COMMANDS_EXP_SIZE) { - fprintf(stderr, - "sizeof(PERSISTENT_DATA.auditCommands) does not have expected size " - "of %u bytes but %zu bytes\n", - PD_AUDIT_COMMANDS_EXP_SIZE, sizeof(pd.auditCommands)); - return EXIT_FAILURE; - } - /* ensure that the NVRAM offset of NV_USER_DYNAMIC is at the expected location so that there's enough memory for re-constructing NVRAM indices etc. into the NVRAM */