When recovering the IMA measurement list after kexec(), currently, the counter
of violations is not restored. This lack causes a mismatch between the real
number of violations and the value reported by the <securityfs>/ima/violations
file.

Restore the violations counter during the IMA measurement list recovery. To
verify if a measurement corresponds to a violation, check if the corresponding
recalculated template data hash is all zeros as read from the kexec buffer.
This check permits avoiding false positives, but it does not account for false
negatives. If the template data hash results in all zeros, it is not counted
as a violation even if it could be.

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

Changes in v2:
- Reworked patch description as suggested by Roberto.
- Added descriptive comment as suggested by Roberto.
- Moved from ima_algo_array[i].digest_size to ARRAY_SIZE() as suggested
  by Roberto.

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

diff --git a/security/integrity/ima/ima_template.c 
b/security/integrity/ima/ima_template.c
index 7034573fb41e..f7749c8499dd 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,27 @@ 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;
+               }
+
+               /*
+                * Check if the current measurement is a violation as reported
+                * in the kexec buffer. In case it is, revert the effect of
+                * ima_calc_field_array_hash(), setting all the calculated
+                * digests to zero, and update the violations counter.
+                */
+               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++) {
+                               memset(entry->digests[i].digest, 0,
+                                      ARRAY_SIZE(entry->digests[i].digest));
                        }
+                       atomic_long_inc(&ima_htable.violations);
                }
 
                entry->pcr = !ima_canonical_fmt ? *(u32 *)(hdr[HDR_PCR].data) :

base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
-- 
2.52.0


Reply via email to