Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ima: verify the previous kernel's IMA buffer lies in addressable RAM

Patch series "Address page fault in ima_restore_measurement_list()", v3.

When the second-stage kernel is booted via kexec with a limiting command
line such as "mem=<size>" we observe a pafe fault that happens.

BUG: unable to handle page fault for address: ffff97793ff47000
RIP: ima_restore_measurement_list+0xdc/0x45a
#PF: error_code(0x0000) not-present page

This happens on x86_64 only, as this is already fixed in aarch64 in
commit: cbf9c4b9617b ("of: check previous kernel's ima-kexec-buffer
against memory bounds")


This patch (of 3):

When the second-stage kernel is booted with a limiting command line (e.g.
"mem=<size>"), the IMA measurement buffer handed over from the previous
kernel may fall outside the addressable RAM of the new kernel. Accessing
such a buffer can fault during early restore.

Introduce a small generic helper, ima_validate_range(), which verifies
that a physical [start, end] range for the previous-kernel IMA buffer lies
within addressable memory:
- On x86, use pfn_range_is_mapped().
- On OF based architectures, use page_is_ram().

Link: https://lkml.kernel.org/r/20251231061609.907170-1-harshit.m.mogalapalli@oracle.com
Link: https://lkml.kernel.org/r/20251231061609.907170-2-harshit.m.mogalapalli@oracle.com
Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
Cc: Alexander Graf <graf@amazon.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Borislav Betkov <bp@alien8.de>
Cc: guoweikang <guoweikang.kernel@gmail.com>
Cc: Henry Willard <henry.willard@oracle.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Bohac <jbohac@suse.cz>
Cc: Joel Granados <joel.granados@kernel.org>
Cc: Jonathan McDowell <noodles@fb.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Paul Webb <paul.x.webb@oracle.com>
Cc: Sohil Mehta <sohil.mehta@intel.com>
Cc: Sourabh Jain <sourabhjain@linux.ibm.com>
Cc: Thomas Gleinxer <tglx@linutronix.de>
Cc: Yifei Liu <yifei.l.liu@oracle.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Harshit Mogalapalli and committed by
Andrew Morton
10d1c75e e896c44a

+36
+1
include/linux/ima.h
··· 69 69 #ifdef CONFIG_HAVE_IMA_KEXEC 70 70 int __init ima_free_kexec_buffer(void); 71 71 int __init ima_get_kexec_buffer(void **addr, size_t *size); 72 + int ima_validate_range(phys_addr_t phys, size_t size); 72 73 #endif 73 74 74 75 #ifdef CONFIG_IMA_SECURE_AND_OR_TRUSTED_BOOT
+35
security/integrity/ima/ima_kexec.c
··· 12 12 #include <linux/kexec.h> 13 13 #include <linux/of.h> 14 14 #include <linux/ima.h> 15 + #include <linux/mm.h> 16 + #include <linux/overflow.h> 15 17 #include <linux/reboot.h> 16 18 #include <asm/page.h> 17 19 #include "ima.h" ··· 295 293 default: 296 294 pr_debug("Error restoring the measurement list: %d\n", rc); 297 295 } 296 + } 297 + 298 + /* 299 + * ima_validate_range - verify a physical buffer lies in addressable RAM 300 + * @phys: physical start address of the buffer from previous kernel 301 + * @size: size of the buffer 302 + * 303 + * On success return 0. On failure returns -EINVAL so callers can skip 304 + * restoring. 305 + */ 306 + int ima_validate_range(phys_addr_t phys, size_t size) 307 + { 308 + unsigned long start_pfn, end_pfn; 309 + phys_addr_t end_phys; 310 + 311 + if (check_add_overflow(phys, (phys_addr_t)size - 1, &end_phys)) 312 + return -EINVAL; 313 + 314 + start_pfn = PHYS_PFN(phys); 315 + end_pfn = PHYS_PFN(end_phys); 316 + 317 + #ifdef CONFIG_X86 318 + if (!pfn_range_is_mapped(start_pfn, end_pfn)) 319 + #else 320 + if (!page_is_ram(start_pfn) || !page_is_ram(end_pfn)) 321 + #endif 322 + { 323 + pr_warn("IMA: previous kernel measurement buffer %pa (size 0x%zx) lies outside available memory\n", 324 + &phys, size); 325 + return -EINVAL; 326 + } 327 + 328 + return 0; 298 329 }