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
