1From 8a6d6299efcffd14c1130942195e6c0d9b50cacd Mon Sep 17 00:00:00 2001 2From: Alexey Makhalov <amakhalov@vmware.com> 3Date: Mon, 20 Jul 2020 23:03:05 +0000 4Subject: [PATCH] efi: Fix use-after-free in halt/reboot path 5MIME-Version: 1.0 6Content-Type: text/plain; charset=UTF-8 7Content-Transfer-Encoding: 8bit 8 9commit 92bfc33db984 ("efi: Free malloc regions on exit") 10introduced memory freeing in grub_efi_fini(), which is 11used not only by exit path but by halt/reboot one as well. 12As result of memory freeing, code and data regions used by 13modules, such as halt, reboot, acpi (used by halt) also got 14freed. After return to module code, CPU executes, filled 15by UEFI firmware (tested with edk2), 0xAFAFAFAF pattern as 16a code. Which leads to #UD exception later. 17 18grub> halt 19!!!! X64 Exception Type - 06(#UD - Invalid Opcode) CPU Apic ID - 00000000 !!!! 20RIP - 0000000003F4EC28, CS - 0000000000000038, RFLAGS - 0000000000200246 21RAX - 0000000000000000, RCX - 00000000061DA188, RDX - 0A74C0854DC35D41 22RBX - 0000000003E10E08, RSP - 0000000007F0F860, RBP - 0000000000000000 23RSI - 00000000064DB768, RDI - 000000000832C5C3 24R8 - 0000000000000002, R9 - 0000000000000000, R10 - 00000000061E2E52 25R11 - 0000000000000020, R12 - 0000000003EE5C1F, R13 - 00000000061E0FF4 26R14 - 0000000003E10D80, R15 - 00000000061E2F60 27DS - 0000000000000030, ES - 0000000000000030, FS - 0000000000000030 28GS - 0000000000000030, SS - 0000000000000030 29CR0 - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000 30CR4 - 0000000000000668, CR8 - 0000000000000000 31DR0 - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000 32DR3 - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400 33GDTR - 00000000079EEA98 0000000000000047, LDTR - 0000000000000000 34IDTR - 0000000007598018 0000000000000FFF, TR - 0000000000000000 35FXSAVE_STATE - 0000000007F0F4C0 36 37Proposal here is to continue to free allocated memory for 38exit boot services path but keep it for halt/reboot path 39as it won't be much security concern here. 40Introduced GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY 41loader flag to be used by efi halt/reboot path. 42 43Signed-off-by: Alexey Makhalov <amakhalov@vmware.com> 44Reviewed-by: Darren Kenny <darren.kenny@oracle.com> 45Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> 46Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com> 47--- 48 grub-core/kern/arm/efi/init.c | 3 +++ 49 grub-core/kern/arm64/efi/init.c | 3 +++ 50 grub-core/kern/efi/efi.c | 3 ++- 51 grub-core/kern/efi/init.c | 1 - 52 grub-core/kern/i386/efi/init.c | 9 +++++++-- 53 grub-core/kern/ia64/efi/init.c | 9 +++++++-- 54 grub-core/kern/riscv/efi/init.c | 3 +++ 55 grub-core/lib/efi/halt.c | 3 ++- 56 include/grub/loader.h | 1 + 57 9 files changed, 28 insertions(+), 7 deletions(-) 58 59diff --git a/grub-core/kern/arm/efi/init.c b/grub-core/kern/arm/efi/init.c 60index 06df60e2f..40c3b467f 100644 61--- a/grub-core/kern/arm/efi/init.c 62+++ b/grub-core/kern/arm/efi/init.c 63@@ -71,4 +71,7 @@ grub_machine_fini (int flags) 64 efi_call_1 (b->close_event, tmr_evt); 65 66 grub_efi_fini (); 67+ 68+ if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) 69+ grub_efi_memory_fini (); 70 } 71diff --git a/grub-core/kern/arm64/efi/init.c b/grub-core/kern/arm64/efi/init.c 72index 6224999ec..5010caefd 100644 73--- a/grub-core/kern/arm64/efi/init.c 74+++ b/grub-core/kern/arm64/efi/init.c 75@@ -57,4 +57,7 @@ grub_machine_fini (int flags) 76 return; 77 78 grub_efi_fini (); 79+ 80+ if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) 81+ grub_efi_memory_fini (); 82 } 83diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c 84index c97969a65..9cfd88d77 100644 85--- a/grub-core/kern/efi/efi.c 86+++ b/grub-core/kern/efi/efi.c 87@@ -157,7 +157,8 @@ grub_efi_get_loaded_image (grub_efi_handle_t image_handle) 88 void 89 grub_reboot (void) 90 { 91- grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); 92+ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN | 93+ GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY); 94 efi_call_4 (grub_efi_system_table->runtime_services->reset_system, 95 GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); 96 for (;;) ; 97diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c 98index 3dfdf2d22..2c31847bf 100644 99--- a/grub-core/kern/efi/init.c 100+++ b/grub-core/kern/efi/init.c 101@@ -80,5 +80,4 @@ grub_efi_fini (void) 102 { 103 grub_efidisk_fini (); 104 grub_console_fini (); 105- grub_efi_memory_fini (); 106 } 107diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c 108index da499aba0..deb2eacd8 100644 109--- a/grub-core/kern/i386/efi/init.c 110+++ b/grub-core/kern/i386/efi/init.c 111@@ -39,6 +39,11 @@ grub_machine_init (void) 112 void 113 grub_machine_fini (int flags) 114 { 115- if (flags & GRUB_LOADER_FLAG_NORETURN) 116- grub_efi_fini (); 117+ if (!(flags & GRUB_LOADER_FLAG_NORETURN)) 118+ return; 119+ 120+ grub_efi_fini (); 121+ 122+ if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) 123+ grub_efi_memory_fini (); 124 } 125diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c 126index b5ecbd091..f1965571b 100644 127--- a/grub-core/kern/ia64/efi/init.c 128+++ b/grub-core/kern/ia64/efi/init.c 129@@ -70,6 +70,11 @@ grub_machine_init (void) 130 void 131 grub_machine_fini (int flags) 132 { 133- if (flags & GRUB_LOADER_FLAG_NORETURN) 134- grub_efi_fini (); 135+ if (!(flags & GRUB_LOADER_FLAG_NORETURN)) 136+ return; 137+ 138+ grub_efi_fini (); 139+ 140+ if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) 141+ grub_efi_memory_fini (); 142 } 143diff --git a/grub-core/kern/riscv/efi/init.c b/grub-core/kern/riscv/efi/init.c 144index 7eb1969d0..38795fe67 100644 145--- a/grub-core/kern/riscv/efi/init.c 146+++ b/grub-core/kern/riscv/efi/init.c 147@@ -73,4 +73,7 @@ grub_machine_fini (int flags) 148 return; 149 150 grub_efi_fini (); 151+ 152+ if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY)) 153+ grub_efi_memory_fini (); 154 } 155diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c 156index 5859f0498..29d413641 100644 157--- a/grub-core/lib/efi/halt.c 158+++ b/grub-core/lib/efi/halt.c 159@@ -28,7 +28,8 @@ 160 void 161 grub_halt (void) 162 { 163- grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); 164+ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN | 165+ GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY); 166 #if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__) && \ 167 !defined(__riscv) 168 grub_acpi_halt (); 169diff --git a/include/grub/loader.h b/include/grub/loader.h 170index 7f82a499f..b20864282 100644 171--- a/include/grub/loader.h 172+++ b/include/grub/loader.h 173@@ -33,6 +33,7 @@ enum 174 { 175 GRUB_LOADER_FLAG_NORETURN = 1, 176 GRUB_LOADER_FLAG_PXE_NOT_UNLOAD = 2, 177+ GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY = 4, 178 }; 179 180 void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), 181-- 1822.26.2 183 184