xref: /OK3568_Linux_fs/buildroot/boot/grub2/0026-efi-Fix-use-after-free-in-halt-reboot-path.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From 8a6d6299efcffd14c1130942195e6c0d9b50cacd Mon Sep 17 00:00:00 2001
2From: Alexey Makhalov <amakhalov@vmware.com>
3Date: Mon, 20 Jul 2020 23:03:05 +0000
4Subject: [PATCH] efi: Fix use-after-free in halt/reboot path
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9commit 92bfc33db984 ("efi: Free malloc regions on exit")
10introduced memory freeing in grub_efi_fini(), which is
11used not only by exit path but by halt/reboot one as well.
12As result of memory freeing, code and data regions used by
13modules, such as halt, reboot, acpi (used by halt) also got
14freed. After return to module code, CPU executes, filled
15by UEFI firmware (tested with edk2), 0xAFAFAFAF pattern as
16a code. Which leads to #UD exception later.
17
18grub> halt
19!!!! X64 Exception Type - 06(#UD - Invalid Opcode)  CPU Apic ID - 00000000 !!!!
20RIP  - 0000000003F4EC28, CS  - 0000000000000038, RFLAGS - 0000000000200246
21RAX  - 0000000000000000, RCX - 00000000061DA188, RDX - 0A74C0854DC35D41
22RBX  - 0000000003E10E08, RSP - 0000000007F0F860, RBP - 0000000000000000
23RSI  - 00000000064DB768, RDI - 000000000832C5C3
24R8   - 0000000000000002, R9  - 0000000000000000, R10 - 00000000061E2E52
25R11  - 0000000000000020, R12 - 0000000003EE5C1F, R13 - 00000000061E0FF4
26R14  - 0000000003E10D80, R15 - 00000000061E2F60
27DS   - 0000000000000030, ES  - 0000000000000030, FS  - 0000000000000030
28GS   - 0000000000000030, SS  - 0000000000000030
29CR0  - 0000000080010033, CR2 - 0000000000000000, CR3 - 0000000007C01000
30CR4  - 0000000000000668, CR8 - 0000000000000000
31DR0  - 0000000000000000, DR1 - 0000000000000000, DR2 - 0000000000000000
32DR3  - 0000000000000000, DR6 - 00000000FFFF0FF0, DR7 - 0000000000000400
33GDTR - 00000000079EEA98 0000000000000047, LDTR - 0000000000000000
34IDTR - 0000000007598018 0000000000000FFF,   TR - 0000000000000000
35FXSAVE_STATE - 0000000007F0F4C0
36
37Proposal here is to continue to free allocated memory for
38exit boot services path but keep it for halt/reboot path
39as it won't be much security concern here.
40Introduced GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY
41loader flag to be used by efi halt/reboot path.
42
43Signed-off-by: Alexey Makhalov <amakhalov@vmware.com>
44Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
45Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
46Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com>
47---
48 grub-core/kern/arm/efi/init.c   | 3 +++
49 grub-core/kern/arm64/efi/init.c | 3 +++
50 grub-core/kern/efi/efi.c        | 3 ++-
51 grub-core/kern/efi/init.c       | 1 -
52 grub-core/kern/i386/efi/init.c  | 9 +++++++--
53 grub-core/kern/ia64/efi/init.c  | 9 +++++++--
54 grub-core/kern/riscv/efi/init.c | 3 +++
55 grub-core/lib/efi/halt.c        | 3 ++-
56 include/grub/loader.h           | 1 +
57 9 files changed, 28 insertions(+), 7 deletions(-)
58
59diff --git a/grub-core/kern/arm/efi/init.c b/grub-core/kern/arm/efi/init.c
60index 06df60e2f..40c3b467f 100644
61--- a/grub-core/kern/arm/efi/init.c
62+++ b/grub-core/kern/arm/efi/init.c
63@@ -71,4 +71,7 @@ grub_machine_fini (int flags)
64   efi_call_1 (b->close_event, tmr_evt);
65
66   grub_efi_fini ();
67+
68+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
69+    grub_efi_memory_fini ();
70 }
71diff --git a/grub-core/kern/arm64/efi/init.c b/grub-core/kern/arm64/efi/init.c
72index 6224999ec..5010caefd 100644
73--- a/grub-core/kern/arm64/efi/init.c
74+++ b/grub-core/kern/arm64/efi/init.c
75@@ -57,4 +57,7 @@ grub_machine_fini (int flags)
76     return;
77
78   grub_efi_fini ();
79+
80+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
81+    grub_efi_memory_fini ();
82 }
83diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c
84index c97969a65..9cfd88d77 100644
85--- a/grub-core/kern/efi/efi.c
86+++ b/grub-core/kern/efi/efi.c
87@@ -157,7 +157,8 @@ grub_efi_get_loaded_image (grub_efi_handle_t image_handle)
88 void
89 grub_reboot (void)
90 {
91-  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
92+  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN |
93+		     GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY);
94   efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
95               GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL);
96   for (;;) ;
97diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
98index 3dfdf2d22..2c31847bf 100644
99--- a/grub-core/kern/efi/init.c
100+++ b/grub-core/kern/efi/init.c
101@@ -80,5 +80,4 @@ grub_efi_fini (void)
102 {
103   grub_efidisk_fini ();
104   grub_console_fini ();
105-  grub_efi_memory_fini ();
106 }
107diff --git a/grub-core/kern/i386/efi/init.c b/grub-core/kern/i386/efi/init.c
108index da499aba0..deb2eacd8 100644
109--- a/grub-core/kern/i386/efi/init.c
110+++ b/grub-core/kern/i386/efi/init.c
111@@ -39,6 +39,11 @@ grub_machine_init (void)
112 void
113 grub_machine_fini (int flags)
114 {
115-  if (flags & GRUB_LOADER_FLAG_NORETURN)
116-    grub_efi_fini ();
117+  if (!(flags & GRUB_LOADER_FLAG_NORETURN))
118+    return;
119+
120+  grub_efi_fini ();
121+
122+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
123+    grub_efi_memory_fini ();
124 }
125diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c
126index b5ecbd091..f1965571b 100644
127--- a/grub-core/kern/ia64/efi/init.c
128+++ b/grub-core/kern/ia64/efi/init.c
129@@ -70,6 +70,11 @@ grub_machine_init (void)
130 void
131 grub_machine_fini (int flags)
132 {
133-  if (flags & GRUB_LOADER_FLAG_NORETURN)
134-    grub_efi_fini ();
135+  if (!(flags & GRUB_LOADER_FLAG_NORETURN))
136+    return;
137+
138+  grub_efi_fini ();
139+
140+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
141+    grub_efi_memory_fini ();
142 }
143diff --git a/grub-core/kern/riscv/efi/init.c b/grub-core/kern/riscv/efi/init.c
144index 7eb1969d0..38795fe67 100644
145--- a/grub-core/kern/riscv/efi/init.c
146+++ b/grub-core/kern/riscv/efi/init.c
147@@ -73,4 +73,7 @@ grub_machine_fini (int flags)
148     return;
149
150   grub_efi_fini ();
151+
152+  if (!(flags & GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY))
153+    grub_efi_memory_fini ();
154 }
155diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c
156index 5859f0498..29d413641 100644
157--- a/grub-core/lib/efi/halt.c
158+++ b/grub-core/lib/efi/halt.c
159@@ -28,7 +28,8 @@
160 void
161 grub_halt (void)
162 {
163-  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
164+  grub_machine_fini (GRUB_LOADER_FLAG_NORETURN |
165+		     GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY);
166 #if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__) && \
167     !defined(__riscv)
168   grub_acpi_halt ();
169diff --git a/include/grub/loader.h b/include/grub/loader.h
170index 7f82a499f..b20864282 100644
171--- a/include/grub/loader.h
172+++ b/include/grub/loader.h
173@@ -33,6 +33,7 @@ enum
174 {
175   GRUB_LOADER_FLAG_NORETURN = 1,
176   GRUB_LOADER_FLAG_PXE_NOT_UNLOAD = 2,
177+  GRUB_LOADER_FLAG_EFI_KEEP_ALLOCATED_MEMORY = 4,
178 };
179
180 void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void),
181--
1822.26.2
183
184