]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
efi: Fix use-after-free in halt/reboot path
authorAlexey Makhalov <amakhalov@vmware.com>
Mon, 20 Jul 2020 23:03:05 +0000 (23:03 +0000)
committerDaniel Kiper <daniel.kiper@oracle.com>
Wed, 29 Jul 2020 14:55:48 +0000 (16:55 +0200)
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 <amakhalov@vmware.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/kern/arm/efi/init.c
grub-core/kern/arm64/efi/init.c
grub-core/kern/efi/efi.c
grub-core/kern/efi/init.c
grub-core/kern/i386/efi/init.c
grub-core/kern/ia64/efi/init.c
grub-core/kern/riscv/efi/init.c
grub-core/lib/efi/halt.c
include/grub/loader.h

index 06df60e2f0e12ee5e53f95f1a821217fc5fcd84e..40c3b467fc6bc447347e7ee48045b96a77458f17 100644 (file)
@@ -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 ();
 }
index 6224999ec9c5cddf2b9a6b39bdcce5c1c2f265bb..5010caefd66c14d4ecfcd942e23781c938677e8d 100644 (file)
@@ -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 ();
 }
index 535e29424e90e98cc054d6f6cfb134fee5280199..e0165e74c587bf6a1a32d3c6358c11db7f535dd0 100644 (file)
@@ -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 (;;) ;
index 3dfdf2d22b02ae8847a3e19a175517d2d71544fa..2c31847bf6db77fab377c90e7ed36897439d6027 100644 (file)
@@ -80,5 +80,4 @@ grub_efi_fini (void)
 {
   grub_efidisk_fini ();
   grub_console_fini ();
-  grub_efi_memory_fini ();
 }
index da499aba04e09138f400ba47d936e5846a244035..deb2eacd8d8c3ae4a52a80d7b211603bb6f9516e 100644 (file)
@@ -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 ();
 }
index b5ecbd09121fd61a0ac38fdcaaa850f5aeaba7e9..f1965571b1dc0dced99c37e8945e913dc3912770 100644 (file)
@@ -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 ();
 }
index 7eb1969d0b0a132098efaca4d57d3495b8c1e2c8..38795fe674189eae19ac687d33627e2d4b6428a6 100644 (file)
@@ -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 ();
 }
index 5859f0498a874071e0376423615e0b70a1840cd1..29d41364168eaeba8e98a5b8ba3908b01aec445b 100644 (file)
@@ -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(__riscv)
   grub_acpi_halt ();
index 7f82a499fd9c025643b7f757ecb489bbac2a285c..b208642821b1381c2cd5573dca7ff3f0fbbf7d70 100644 (file)
@@ -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),