From 1fc47c7f906842ae80291736498d8232dd4a3efb Mon Sep 17 00:00:00 2001 From: Wentao Guan Date: Sun, 25 Aug 2024 19:12:17 +0800 Subject: [PATCH] efi: Fix use-after-free in halt/reboot path commit 92bfc33db984 ("efi: Free malloc regions on exit") introduced memory freeing in grub_efi_fini(), which is used not only by exit path but by halt/reboot one as well. As result of memory freeing, code and data regions used by modules, such as halt, reboot, acpi (used by halt) also got freed. After return to module code, CPU executes, filled by UEFI firmware (tested with edk2), 0xAFAFAFAF pattern as a code. Which leads to #UD exception later. grub> halt !!!! X64 Exception Type - 06(#UD - Invalid Opcode) CPU Apic ID - 00000000 !!!! RIP - 0000000003F4EC28, CS - 0000000000000038, RFLAGS - 0000000000200246 RAX - 0000000000000000, RCX - 00000000061DA188, RDX - 0A74C0854DC35D41 RBX - 0000000003E10E08, RSP - 0000000007F0F860, RBP - 0000000000000000 RSI - 00000000064DB768, RDI - 000000000832C5C3 R8 - 0000000000000002, R9 - 0000000000000000, R10 - 00000000061E2E52 R11 - 0000000000000020, R12 - 0000000003EE5C1F, R13 - 00000000061E0FF4 R14 - 0000000003E10D80, R15 - 00000000061E2F60 DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 GS - 0000000000000030, SS - 0000000000000030 CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000 CR4 - 0000000000000668, CR8 - 0000000000000000 DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 GDTR - 00000000079EEA98 0000000000000047, LDTR - 0000000000000000 IDTR - 0000000007598018 0000000000000FFF, TR - 0000000000000000 FXSAVE_STATE - 0000000007F0F4C0 Proposal here is to continue to free allocated memory for exit boot services path but keep it for halt/reboot path as it won't be much security concern here. Introduced GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY loader flag to be used by efi halt/reboot path. Signed-off-by: Alexey Makhalov Reviewed-by: Darren Kenny Reviewed-by: Daniel Kiper Signed-off-by: Wentao Guan --- GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm/efi/init.c | 3 +++ GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm64/efi/init.c | 3 +++ GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c | 3 ++- GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/init.c | 1 - GRUB2/MOD_SRC/grub-2.04/grub-core/kern/i386/efi/init.c | 9 +++++++-- GRUB2/MOD_SRC/grub-2.04/grub-core/kern/ia64/efi/init.c | 9 +++++++-- GRUB2/MOD_SRC/grub-2.04/grub-core/kern/riscv/efi/init.c | 3 +++ GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c | 3 ++- GRUB2/MOD_SRC/grub-2.04/include/grub/loader.h | 1 + 9 files changed, 28 insertions(+), 7 deletions(-) diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm/efi/init.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm/efi/init.c index 06df60e2..40c3b467 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm/efi/init.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm/efi/init.c @@ -71,4 +71,7 @@ grub_machine_fini (int flags) efi_call_1 (b->close_event, tmr_evt); grub_efi_fini (); + + if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) + grub_efi_memory_fini (); } diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm64/efi/init.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm64/efi/init.c index 6224999e..5010caef 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm64/efi/init.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/arm64/efi/init.c @@ -57,4 +57,7 @@ grub_machine_fini (int flags) return; grub_efi_fini (); + + if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) + grub_efi_memory_fini (); } diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c index 64c73916..128a87b4 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/efi.c @@ -157,7 +157,8 @@ grub_efi_get_loaded_image (grub_efi_handle_t image_handle) void grub_reboot (void) { - grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN | + GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY); efi_call_4 (grub_efi_system_table->runtime_services->reset_system, GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); for (;;) ; diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/init.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/init.c index 3dfdf2d2..2c31847b 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/init.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/efi/init.c @@ -80,5 +80,4 @@ grub_efi_fini (void) { grub_efidisk_fini (); grub_console_fini (); - grub_efi_memory_fini (); } diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/i386/efi/init.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/i386/efi/init.c index da499aba..deb2eacd 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/i386/efi/init.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/i386/efi/init.c @@ -39,6 +39,11 @@ grub_machine_init (void) void grub_machine_fini (int flags) { - if (flags & GRUB_LOADER_FLAG_NORETURN) - grub_efi_fini (); + if (!(flags & GRUB_LOADER_FLAG_NORETURN)) + return; + + grub_efi_fini (); + + if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) + grub_efi_memory_fini (); } diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/ia64/efi/init.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/ia64/efi/init.c index b5ecbd09..f1965571 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/ia64/efi/init.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/ia64/efi/init.c @@ -70,6 +70,11 @@ grub_machine_init (void) void grub_machine_fini (int flags) { - if (flags & GRUB_LOADER_FLAG_NORETURN) - grub_efi_fini (); + if (!(flags & GRUB_LOADER_FLAG_NORETURN)) + return; + + grub_efi_fini (); + + if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) + grub_efi_memory_fini (); } diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/riscv/efi/init.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/riscv/efi/init.c index 7eb1969d..38795fe6 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/riscv/efi/init.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/kern/riscv/efi/init.c @@ -73,4 +73,7 @@ grub_machine_fini (int flags) return; grub_efi_fini (); + + if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) + grub_efi_memory_fini (); } diff --git a/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c b/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c index 6d490d90..bb8b577f 100644 --- a/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c +++ b/GRUB2/MOD_SRC/grub-2.04/grub-core/lib/efi/halt.c @@ -28,7 +28,8 @@ void grub_halt (void) { - grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); + grub_machine_fini (GRUB_LOADER_FLAG_NORETURN | + GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY); #if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__mips__) &&\ !defined(__loongarch__) && !defined(__riscv) grub_acpi_halt (); diff --git a/GRUB2/MOD_SRC/grub-2.04/include/grub/loader.h b/GRUB2/MOD_SRC/grub-2.04/include/grub/loader.h index 7f82a499..b2086428 100644 --- a/GRUB2/MOD_SRC/grub-2.04/include/grub/loader.h +++ b/GRUB2/MOD_SRC/grub-2.04/include/grub/loader.h @@ -33,6 +33,7 @@ enum { GRUB_LOADER_FLAG_NORETURN = 1, GRUB_LOADER_FLAG_PXE_NOT_UNLOAD = 2, + GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY = 4, }; void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),