ima_restore_measurement_list() parses the measurement list persisted across
kexec. It computes the parse end directly from the blob:
bufendp = buf + khdr->buffer_size;
khdr->buffer_size is a u64 read straight from the persisted buffer. The
only length checks in the function are size >= sizeof(*khdr), version == 1
and count -- none relates buffer_size to size, the actual buffer size the
caller (ima_load_kexec_buffer()) obtained from the ima-kexec-buffer region.
ima_parse_buf() bounds every field read to bufendp, so a blob whose
internal buffer_size exceeds the real size makes the parse loop read past
the end of the buffer (CWE-125).
The buffer's memory range is validated against addressable RAM by
commit cbf9c4b9617b ("of: check previous kernel's ima-kexec-buffer
against memory bounds") and commit c5489d04337b ("x86/kexec: add a
sanity check on previous kernel's ima kexec buffer"), but the blob's
own declared size is never clamped to it. Reject a buffer_size larger
than size before the loop.
This is on the boot-time kexec-restore path (__init) and the buffer comes
from the previous kernel, so triggering it requires control of the
persisted buffer; it is an out-of-bounds read only.
Fixes: 94c3aac567a9 ("ima: on soft reboot, restore the measurement list")
Assisted-by: copilot-cli:claude-opus-4-6 frama-c
Signed-off-by: Fabrice Derepas <[email protected]>
---
Tested under KASAN (CONFIG_KASAN_GENERIC, x86-64) with a KUnit case that calls
ima_restore_measurement_list() on a 24-byte buffer whose header declares
buffer_size = 0x1000. On an unpatched kernel this takes a slab-out-of-bounds
read of size 4 in ima_parse_buf() from ima_restore_measurement_list(); with
this patch the buffer is rejected and the case passes with no KASAN report.
The test is not included here (there is no upstream IMA KUnit suite yet); I'm
happy to submit it separately if useful.
security/integrity/ima/ima_template.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/security/integrity/ima/ima_template.c
b/security/integrity/ima/ima_template.c
index 7034573..2467cae 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -450,6 +450,11 @@ int ima_restore_measurement_list(loff_t size, void *buf)
return -EINVAL;
}
+ if (khdr->buffer_size > size) {
+ pr_err("attempting to restore a corrupted measurement list");
+ return -EINVAL;
+ }
+
bitmap_zero(hdr_mask, HDR__LAST);
bitmap_set(hdr_mask, HDR_PCR, 1);
bitmap_set(hdr_mask, HDR_DIGEST, 1);
base-commit: f5bbbfec59b4e2fb7520a91de3df8a6174325d6a
--
2.53.0