diff mbox series

[v2] ima-evm-utils: Improve ima_measurement matching on busy system with >1 banks

Message ID 20210209122106.870973-1-stefanb@linux.ibm.com (mailing list archive)
State New, archived
Headers show
Series [v2] ima-evm-utils: Improve ima_measurement matching on busy system with >1 banks | expand

Commit Message

Stefan Berger Feb. 9, 2021, 12:21 p.m. UTC
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@linux.ibm.com>
---
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(-)

Comments

Mimi Zohar Feb. 9, 2021, 1:23 p.m. UTC | #1
On Tue, 2021-02-09 at 07:21 -0500, Stefan Berger wrote:
> 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@linux.ibm.com>
> ---
> v1->v2:
>  - Reporting entry number that resulted in a match when in verbose mode

Thanks,  Stefan.   This and your other two patches are now queued in
next-testing.

Mimi
diff mbox series

Patch

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;
 	}