dcavalca / rpms / grub2

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