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>
b05195
[rharwood: fix backport issue with exit/reboot]
b05195
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
c4e390
---
c4e390
 grub-core/kern/arm/efi/init.c  | 3 +++
b05195
 grub-core/kern/efi/efi.c       | 3 ++-
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 +
b05195
 6 files changed, 22 insertions(+), 6 deletions(-)
c4e390
c4e390
diff --git a/grub-core/kern/arm/efi/init.c b/grub-core/kern/arm/efi/init.c
b05195
index 06df60e2f..40c3b467f 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
b05195
index 42c68307f..72080c4f6 100644
c4e390
--- a/grub-core/kern/efi/efi.c
c4e390
+++ b/grub-core/kern/efi/efi.c
b05195
@@ -162,7 +162,8 @@ grub_exit (int retval)
c4e390
   if (retval == 0)
c4e390
     rc = GRUB_EFI_SUCCESS;
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);
b05195
   efi_call_4 (grub_efi_system_table->boot_services->exit,
b05195
               grub_efi_image_handle, rc, 0, 0);
c4e390
   for (;;) ;
c4e390
diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c
b05195
index a28316cc6..46476e27e 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
b05195
index b5ecbd091..f1965571b 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
b05195
index e9441c844..a69a77681 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
b05195
index 7f82a499f..b20864282 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),