[PATCH] ima: correctly recover number of violations after kexec

Enrico Bravi <[email protected]> Fri, 19 Jun 2026 21:14:53 +0200
Newsgroups org.kernel.vger.linux-integrity
Message-ID <[email protected]>
When recovering the measurement list after kexec(), the number of
violations is not recovered as well, causing a mismatch between the
number reported by the <securityfs>/ima/violations user interface and
the actual value. In addition, currently it is assumed that when
recovering an entry, this is a violation if the template data hash
read from the kexec buffer is an all-zero hash, which can actually be a
valid hash.

Verify that an all-zero hash corresponds to a violation and consequently
correctly recover the number of violations.

Reported-by: Roberto Sassu <[email protected]>
Closes: https://github.com/linux-integrity/linux/issues/13
Signed-off-by: Enrico Bravi <[email protected]>

---
 security/integrity/ima/ima_template.c | 28 ++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c
index 7034573fb41e..147f228ed246 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -430,6 +430,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)
 	DECLARE_BITMAP(hdr_mask, HDR__LAST);
 	unsigned long count = 0;
 	int ret = 0;
+	int i;
 
 	if (!buf || size < sizeof(*khdr))
 		return 0;
@@ -515,15 +516,28 @@ int ima_restore_measurement_list(loff_t size, void *buf)
 		if (ret < 0)
 			break;
 
-		if (memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero))) {
-			ret = ima_calc_field_array_hash(
-						&entry->template_data[0],
+		ret = ima_calc_field_array_hash(&entry->template_data[0],
 						entry);
-			if (ret < 0) {
-				pr_err("cannot calculate template digest\n");
-				ret = -EINVAL;
-				break;
+		if (ret < 0) {
+			pr_err("cannot calculate template digest\n");
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!memcmp(hdr[HDR_DIGEST].data, zero, sizeof(zero)) &&
+		    memcmp(entry->digests[ima_sha1_idx].digest, zero, sizeof(zero))) {
+			for (i = 0; i < NR_BANKS(ima_tpm_chip) + ima_extra_slots; i++) {
+				/* Unmapped TPM algorithms */
+				if (!ima_algo_array[i].tfm) {
+					memset(entry->digests[i].digest, 0,
+					       TPM_DIGEST_SIZE);
+					continue;
+				}
+
+				memset(entry->digests[i].digest, 0,
+				       ima_algo_array[i].digest_size);
 			}
+			atomic_long_inc(&ima_htable.violations);
 		}
 
 		entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :

base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
-- 
2.52.0