dcavalca / rpms / grub2

Forked from rpms/grub2 3 years ago
Clone

Blame SOURCES/0306-efi-Fix-use-after-free-in-halt-reboot-path.patch

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