dcavalca / rpms / grub2

Forked from rpms/grub2 2 years ago
Clone

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

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