When a system is very busy with IMA taking measurements into more than one bank, then we often do not get the PCR 10 values of the sha1 bank that represents the same log entry as the reading of the PCR value of the sha256 bank. In other words, the reading of the PCR 10 value from the sha1 bank may represent the PCR 10 state at the time of the n-th entry in the log while the reading of the PCR 10 value from the sha256 bank may represent the state at the time of a later-than-n entry. The result currently is that the PCR measurements do not match and on a busy system the tool may not easily report a successful match. This patch fixes this issue by separating the TPM bank comparison for each one of the banks being looked and using a bit mask for checking which banks have already been matched. Once the mask has become 0 all PCR banks have been successfully matched. A run on a busy system may result in the output as follows indicating PCR bank matches at the n-th entry for the sha1 bank and at a later entry, possibly n + 1 or n + 2 or so, for the sha256 bank. The output is interleaved with a match of the sha1 bank against 'padded matching'. $ evmctl ima_measurement --ignore-violations /sys/kernel/security/ima/binary_runtime_measurements -v sha1: PCRAgg 10: 381cc6139e2fbda76037ec0946089aeccaaa5374 sha1: TPM PCR-10: 381cc6139e2fbda76037ec0946089aeccaaa5374 sha1 PCR-10: succeed at entry 4918 sha1: PCRAgg 10: 381cc6139e2fbda76037ec0946089aeccaaa5374 sha1: TPM PCR-10: 381cc6139e2fbda76037ec0946089aeccaaa5374 sha1 PCR-10: succeed at entry 4918 [...] sha256: PCRAgg 10: c21dcb7098b3d7627f7aaeddf8aff68a65209027274d82af52be2fd302193eb7 sha256: TPM PCR-10: c21dcb7098b3d7627f7aaeddf8aff68a65209027274d82af52be2fd302193eb7 sha256 PCR-10: succeed at entry 4922 Matched per TPM bank calculated digest(s). Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx> --- v1->v2: - Reporting entry number that resulted in a match when in verbose mode --- src/evmctl.c | 57 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/src/evmctl.c b/src/evmctl.c index 1815f55..f18eaae 100644 --- a/src/evmctl.c +++ b/src/evmctl.c @@ -1594,10 +1594,15 @@ static struct tpm_bank_info *init_tpm_banks(int *num_banks) /* * Compare the calculated TPM PCR banks against the PCR values read. + * The banks_mask parameter allows to select which banks to consider. + * A banks_maks of 0x3 would consider banks 1 and 2, 0x2 would only + * consider the 2nd bank, ~0 would consider all banks. + * * On failure to match any TPM bank, fail comparison. */ static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank, - struct tpm_bank_info *tpm_bank) + struct tpm_bank_info *tpm_bank, + unsigned int banks_mask, unsigned long entry_num) { int i, j; int ret = 0; @@ -1605,6 +1610,9 @@ static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank, for (i = 0; i < num_banks; i++) { if (!bank[i].supported || !tpm_bank[i].supported) continue; + /* do we need to look at the n-th bank ? */ + if ((banks_mask & (1 << i)) == 0) + continue; for (j = 0; j < NUM_PCRS; j++) { if (memcmp(bank[i].pcr[j], zero, bank[i].digest_size) == 0) @@ -1625,8 +1633,8 @@ static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank, log_dump(tpm_bank[i].pcr[j], tpm_bank[i].digest_size); if (!ret) - log_info("%s PCR-%d: succeed\n", - bank[i].algo_name, j); + log_info("%s PCR-%d: succeed at entry %lu\n", + bank[i].algo_name, j, entry_num); else log_info("%s: PCRAgg %d does not match TPM PCR-%d\n", bank[i].algo_name, j, j); @@ -1941,6 +1949,9 @@ static int ima_measurement(const char *file) int num_banks = 0; int tpmbanks = 1; int first_record = 1; + unsigned int pseudo_padded_banks_mask, pseudo_banks_mask; + unsigned long entry_num = 0; + int c; struct template_entry entry = { .template = 0 }; FILE *fp; @@ -1974,7 +1985,12 @@ static int ima_measurement(const char *file) if (read_tpm_banks(num_banks, tpm_banks) != 0) tpmbanks = 0; + /* A mask where each bit represents the banks to check against */ + pseudo_banks_mask = (1 << num_banks) - 1; + pseudo_padded_banks_mask = pseudo_banks_mask; + while (fread(&entry.header, sizeof(entry.header), 1, fp)) { + entry_num++; if (entry.header.name_len > TCG_EVENT_NAME_LEN_MAX) { log_err("%d ERROR: event name too long!\n", entry.header.name_len); @@ -2086,18 +2102,33 @@ static int ima_measurement(const char *file) if (!tpmbanks) continue; - /* The measurement list might contain too many entries, - * compare the re-calculated TPM PCR values after each - * extend. - */ - err = compare_tpm_banks(num_banks, pseudo_banks, tpm_banks); - if (!err) + for (c = 0; c < num_banks; c++) { + if ((pseudo_banks_mask & (1 << c)) == 0) + continue; + /* The measurement list might contain too many entries, + * compare the re-calculated TPM PCR values after each + * extend. + */ + err = compare_tpm_banks(num_banks, pseudo_banks, + tpm_banks, 1 << c, entry_num); + if (!err) + pseudo_banks_mask ^= (1 << c); + } + if (pseudo_banks_mask == 0) break; - /* Compare against original SHA1 zero padded TPM PCR values */ - err_padded = compare_tpm_banks(num_banks, pseudo_padded_banks, - tpm_banks); - if (!err_padded) + for (c = 0; c < num_banks; c++) { + if ((pseudo_padded_banks_mask & (1 << c)) == 0) + continue; + /* Compare against original SHA1 zero padded TPM PCR values */ + err_padded = compare_tpm_banks(num_banks, + pseudo_padded_banks, + tpm_banks, + 1 << c, entry_num); + if (!err_padded) + pseudo_padded_banks_mask ^= (1 << c); + } + if (pseudo_padded_banks_mask == 0) break; } -- 2.29.2