dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone
9723a8
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
c294fc
From: Alexey Makhalov <amakhalov@vmware.com>
c294fc
Date: Mon, 20 Jul 2020 23:03:05 +0000
9723a8
Subject: [PATCH] efi: Fix use-after-free in halt/reboot path
c294fc
c294fc
commit 92bfc33db984 ("efi: Free malloc regions on exit")
c294fc
introduced memory freeing in grub_efi_fini(), which is
c294fc
used not only by exit path but by halt/reboot one as well.
c294fc
As result of memory freeing, code and data regions used by
c294fc
modules, such as halt, reboot, acpi (used by halt) also got
c294fc
freed. After return to module code, CPU executes, filled
c294fc
by UEFI firmware (tested with edk2), 0xAFAFAFAF pattern as
c294fc
a code. Which leads to #UD exception later.
c294fc
c294fc
grub> halt
c294fc
!!!! X64 Exception Type - 06(#UD - Invalid Opcode)  CPU Apic ID - 00000000 !!!!
c294fc
RIP  - 0000000003F4EC28, CS  - 0000000000000038, RFLAGS - 0000000000200246
c294fc
RAX  - 0000000000000000, RCX - 00000000061DA188, RDX - 0A74C0854DC35D41
c294fc
RBX  - 0000000003E10E08, RSP - 0000000007F0F860, RBP - 0000000000000000
c294fc
RSI  - 00000000064DB768, RDI - 000000000832C5C3
c294fc
R8   - 0000000000000002, R9  - 0000000000000000, R10 - 00000000061E2E52
c294fc
R11  - 0000000000000020, R12 - 0000000003EE5C1F, R13 - 00000000061E0FF4
c294fc
R14  - 0000000003E10D80, R15 - 00000000061E2F60
c294fc
DS   - 0000000000000030, ES  - 0000000000000030, FS  - 0000000000000030
c294fc
GS   - 0000000000000030, SS  - 0000000000000030
c294fc
CR0  - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000
c294fc
CR4  - 0000000000000668, CR8 - 0000000000000000
c294fc
DR0  - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
c294fc
DR3  - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
c294fc
GDTR - 00000000079EEA98 0000000000000047, LDTR - 0000000000000000
c294fc
IDTR - 0000000007598018 0000000000000FFF,   TR - 0000000000000000
c294fc
FXSAVE_STATE - 0000000007F0F4C0
c294fc
c294fc
Proposal here is to continue to free allocated memory for
c294fc
exit boot services path but keep it for halt/reboot path
c294fc
as it won't be much security concern here.
c294fc
Introduced GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY
c294fc
loader flag to be used by efi halt/reboot path.
c294fc
c294fc
Signed-off-by: Alexey Makhalov <amakhalov@vmware.com>
c294fc
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
c294fc
---
c294fc
 grub-core/kern/arm/efi/init.c   | 3 +++
c294fc
 grub-core/kern/arm64/efi/init.c | 3 +++
c294fc
 grub-core/kern/efi/efi.c        | 3 ++-
c294fc
 grub-core/kern/efi/init.c       | 1 -
c294fc
 grub-core/kern/i386/efi/init.c  | 9 +++++++--
c294fc
 grub-core/kern/ia64/efi/init.c  | 9 +++++++--
c294fc
 grub-core/lib/efi/halt.c        | 3 ++-
c294fc
 include/grub/loader.h           | 1 +
c294fc
 8 files changed, 25 insertions(+), 7 deletions(-)
c294fc
c294fc
diff --git a/grub-core/kern/arm/efi/init.c b/grub-core/kern/arm/efi/init.c
c294fc
index 06df60e2f0e..40c3b467fc6 100644
c294fc
--- a/grub-core/kern/arm/efi/init.c
c294fc
+++ b/grub-core/kern/arm/efi/init.c
c294fc
@@ -71,4 +71,7 @@ grub_machine_fini (int flags)
c294fc
   efi_call_1 (b->close_event, tmr_evt);
c294fc
 
c294fc
   grub_efi_fini ();
c294fc
+
c294fc
+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
c294fc
+    grub_efi_memory_fini ();
c294fc
 }
c294fc
diff --git a/grub-core/kern/arm64/efi/init.c b/grub-core/kern/arm64/efi/init.c
c294fc
index 6224999ec9c..5010caefd66 100644
c294fc
--- a/grub-core/kern/arm64/efi/init.c
c294fc
+++ b/grub-core/kern/arm64/efi/init.c
c294fc
@@ -57,4 +57,7 @@ grub_machine_fini (int flags)
c294fc
     return;
c294fc
 
c294fc
   grub_efi_fini ();
c294fc
+
c294fc
+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
c294fc
+    grub_efi_memory_fini ();
c294fc
 }
c294fc
diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
c294fc
index 03de9cb14e7..5dfcf943322 100644
c294fc
--- a/grub-core/kern/efi/efi.c
c294fc
+++ b/grub-core/kern/efi/efi.c
c294fc
@@ -157,7 +157,8 @@ grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
c294fc
 void
c294fc
 grub_reboot (void)
c294fc
 {
c294fc
-  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
c294fc
+  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN |
c294fc
+		     GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY);
c294fc
   efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
c294fc
               GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
c294fc
   for (;;) ;
c294fc
diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
c294fc
index e6183a4c44d..79243b364a1 100644
c294fc
--- a/grub-core/kern/efi/init.c
c294fc
+++ b/grub-core/kern/efi/init.c
c294fc
@@ -136,5 +136,4 @@ grub_efi_fini (void)
c294fc
 {
c294fc
   grub_efidisk_fini ();
c294fc
   grub_console_fini ();
c294fc
-  grub_efi_memory_fini ();
c294fc
 }
c294fc
diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c
c294fc
index a28316cc640..46476e27eae 100644
c294fc
--- a/grub-core/kern/i386/efi/init.c
c294fc
+++ b/grub-core/kern/i386/efi/init.c
c294fc
@@ -38,6 +38,11 @@ grub_machine_init (void)
c294fc
 void
c294fc
 grub_machine_fini (int flags)
c294fc
 {
c294fc
-  if (flags & GRUB_LOADER_FLAG_NORETURN)
c294fc
-    grub_efi_fini ();
c294fc
+  if (!(flags & GRUB_LOADER_FLAG_NORETURN))
c294fc
+    return;
c294fc
+
c294fc
+  grub_efi_fini ();
c294fc
+
c294fc
+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
c294fc
+    grub_efi_memory_fini ();
c294fc
 }
c294fc
diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c
c294fc
index b5ecbd09121..f1965571b1d 100644
c294fc
--- a/grub-core/kern/ia64/efi/init.c
c294fc
+++ b/grub-core/kern/ia64/efi/init.c
c294fc
@@ -70,6 +70,11 @@ grub_machine_init (void)
c294fc
 void
c294fc
 grub_machine_fini (int flags)
c294fc
 {
c294fc
-  if (flags & GRUB_LOADER_FLAG_NORETURN)
c294fc
-    grub_efi_fini ();
c294fc
+  if (!(flags & GRUB_LOADER_FLAG_NORETURN))
c294fc
+    return;
c294fc
+
c294fc
+  grub_efi_fini ();
c294fc
+
c294fc
+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
c294fc
+    grub_efi_memory_fini ();
c294fc
 }
c294fc
diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c
c294fc
index e9441c844ac..a69a77681e3 100644
c294fc
--- a/grub-core/lib/efi/halt.c
c294fc
+++ b/grub-core/lib/efi/halt.c
c294fc
@@ -28,7 +28,8 @@
c294fc
 void
c294fc
 grub_halt (void)
c294fc
 {
c294fc
-  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
c294fc
+  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN |
c294fc
+		     GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY);
c294fc
 #if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__)
c294fc
   grub_acpi_halt ();
c294fc
 #endif
c294fc
diff --git a/include/grub/loader.h b/include/grub/loader.h
c294fc
index 7f82a499fd9..b208642821b 100644
c294fc
--- a/include/grub/loader.h
c294fc
+++ b/include/grub/loader.h
c294fc
@@ -33,6 +33,7 @@ enum
c294fc
 {
c294fc
   GRUB_LOADER_FLAG_NORETURN = 1,
c294fc
   GRUB_LOADER_FLAG_PXE_NOT_UNLOAD = 2,
c294fc
+  GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY = 4,
c294fc
 };
c294fc
 
c294fc
 void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),