]> git.proxmox.com Git - efi-boot-shim.git/blame - replacements.c
Closes: #936009
[efi-boot-shim.git] / replacements.c
CommitLineData
031e5cce 1// SPDX-License-Identifier: BSD-2-Clause-Patent
cbef697a
PJ
2/*
3 * shim - trivial UEFI first-stage bootloader
4 *
031e5cce 5 * Copyright Red Hat, Inc
cbef697a
PJ
6 */
7
8/* Chemical agents lend themselves to covert use in sabotage against
9 * which it is exceedingly difficult to visualize any really effective
10 * defense... I will not dwell upon this use of CBW because, as one
11 * pursues the possibilities of such covert uses, one discovers that the
12 * scenarios resemble that in which the components of a nuclear weapon
13 * are smuggled into New York City and assembled in the basement of the
14 * Empire State Building.
15 * In other words, once the possibility is recognized to exist, about
16 * all that one can do is worry about it.
17 * -- Dr. Ivan L Bennett, Jr., testifying before the Subcommittee on
18 * National Security Policy and Scientific Developments, November 20,
19 * 1969.
20 */
cbef697a 21#include "shim.h"
cbef697a
PJ
22
23static EFI_SYSTEM_TABLE *systab;
24
f892ac66
MTL
25EFI_SYSTEM_TABLE *
26get_active_systab(void)
27{
28 if (systab)
29 return systab;
30 return ST;
31}
32
cf90edff 33static typeof(systab->BootServices->LoadImage) system_load_image;
cbef697a
PJ
34static typeof(systab->BootServices->StartImage) system_start_image;
35static typeof(systab->BootServices->Exit) system_exit;
8529e0f7 36#if !defined(DISABLE_EBS_PROTECTION)
cbef697a 37static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
8529e0f7 38#endif /* !defined(DISABLE_EBS_PROTECTION) */
cbef697a 39
cf90edff
PJ
40static EFI_HANDLE last_loaded_image;
41
98a99578 42void
cbef697a
PJ
43unhook_system_services(void)
44{
277127d1
AB
45 if (!systab)
46 return;
47
cf90edff 48 systab->BootServices->LoadImage = system_load_image;
cbef697a 49 systab->BootServices->StartImage = system_start_image;
8529e0f7 50#if !defined(DISABLE_EBS_PROTECTION)
cbef697a 51 systab->BootServices->ExitBootServices = system_exit_boot_services;
8529e0f7
SM
52#endif /* !defined(DISABLE_EBS_PROTECTION) */
53 BS = systab->BootServices;
cbef697a
PJ
54}
55
cf90edff
PJ
56static EFI_STATUS EFIAPI
57load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
58 EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer,
59 UINTN SourceSize, EFI_HANDLE *ImageHandle)
60{
f892ac66 61 EFI_STATUS efi_status;
cf90edff 62
f892ac66 63 unhook_system_services();
8529e0f7
SM
64 efi_status = BS->LoadImage(BootPolicy, ParentImageHandle, DevicePath,
65 SourceBuffer, SourceSize, ImageHandle);
cf90edff 66 hook_system_services(systab);
f892ac66 67 if (EFI_ERROR(efi_status))
cf90edff
PJ
68 last_loaded_image = NULL;
69 else
70 last_loaded_image = *ImageHandle;
f892ac66 71 return efi_status;
cf90edff
PJ
72}
73
cbef697a 74static EFI_STATUS EFIAPI
f892ac66 75replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
cbef697a 76{
f892ac66 77 EFI_STATUS efi_status;
cbef697a 78 unhook_system_services();
cf90edff 79
cf90edff
PJ
80 if (image_handle == last_loaded_image) {
81 loader_is_participating = 1;
82 uninstall_shim_protocols();
83 }
8529e0f7 84 efi_status = BS->StartImage(image_handle, exit_data_size, exit_data);
f892ac66 85 if (EFI_ERROR(efi_status)) {
cf90edff 86 if (image_handle == last_loaded_image) {
f892ac66 87 EFI_STATUS efi_status2 = install_shim_protocols();
cf90edff 88
f892ac66
MTL
89 if (EFI_ERROR(efi_status2)) {
90 console_print(L"Something has gone seriously wrong: %r\n",
91 efi_status2);
92 console_print(L"shim cannot continue, sorry.\n");
b6f94dbe 93 msleep(5000000);
8529e0f7
SM
94 RT->ResetSystem(EfiResetShutdown,
95 EFI_SECURITY_VIOLATION,
96 0, NULL);
cf90edff
PJ
97 }
98 }
cbef697a 99 hook_system_services(systab);
cf90edff
PJ
100 loader_is_participating = 0;
101 }
f892ac66 102 return efi_status;
cbef697a
PJ
103}
104
031e5cce 105#if !defined(DISABLE_EBS_PROTECTION)
cbef697a
PJ
106static EFI_STATUS EFIAPI
107exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
108{
f892ac66
MTL
109 if (loader_is_participating ||
110 verification_method == VERIFIED_BY_HASH) {
cbef697a 111 unhook_system_services();
f892ac66 112 EFI_STATUS efi_status;
8529e0f7 113 efi_status = BS->ExitBootServices(image_key, map_key);
f892ac66 114 if (EFI_ERROR(efi_status))
cbef697a 115 hook_system_services(systab);
f892ac66 116 return efi_status;
cbef697a
PJ
117 }
118
f892ac66
MTL
119 console_print(L"Bootloader has not verified loaded image.\n");
120 console_print(L"System is compromised. halting.\n");
b6f94dbe 121 msleep(5000000);
8529e0f7 122 RT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL);
cbef697a
PJ
123 return EFI_SECURITY_VIOLATION;
124}
031e5cce 125#endif /* !defined(DISABLE_EBS_PROTECTION) */
cbef697a
PJ
126
127static EFI_STATUS EFIAPI
1042fd7c 128do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
d3819813 129 UINTN ExitDataSize, CHAR16 *ExitData)
cbef697a 130{
f892ac66 131 EFI_STATUS efi_status;
cbef697a 132
d3819813
MTL
133 shim_fini();
134
031e5cce
SM
135 restore_loaded_image();
136
8529e0f7
SM
137 efi_status = BS->Exit(ImageHandle, ExitStatus,
138 ExitDataSize, ExitData);
f892ac66
MTL
139 if (EFI_ERROR(efi_status)) {
140 EFI_STATUS efi_status2 = shim_init();
d3819813 141
f892ac66
MTL
142 if (EFI_ERROR(efi_status2)) {
143 console_print(L"Something has gone seriously wrong: %r\n",
144 efi_status2);
145 console_print(L"shim cannot continue, sorry.\n");
b6f94dbe 146 msleep(5000000);
8529e0f7
SM
147 RT->ResetSystem(EfiResetShutdown,
148 EFI_SECURITY_VIOLATION, 0, NULL);
d3819813
MTL
149 }
150 }
f892ac66 151 return efi_status;
cbef697a
PJ
152}
153
cbef697a
PJ
154void
155hook_system_services(EFI_SYSTEM_TABLE *local_systab)
156{
cbef697a 157 systab = local_systab;
8529e0f7 158 BS = systab->BootServices;
cbef697a
PJ
159
160 /* We need to hook various calls to make this work... */
161
cf90edff
PJ
162 /* We need LoadImage() hooked so that fallback.c can load shim
163 * without having to fake LoadImage as well. This allows it
164 * to call the system LoadImage(), and have us track the output
f892ac66
MTL
165 * and mark loader_is_participating in replacement_start_image. This
166 * means anything added by fallback has to be verified by the system
167 * db, which we want to preserve anyway, since that's all launching
cf90edff
PJ
168 * through BDS gives us. */
169 system_load_image = systab->BootServices->LoadImage;
170 systab->BootServices->LoadImage = load_image;
171
cbef697a
PJ
172 /* we need StartImage() so that we can allow chain booting to an
173 * image trusted by the firmware */
174 system_start_image = systab->BootServices->StartImage;
f892ac66 175 systab->BootServices->StartImage = replacement_start_image;
cbef697a 176
031e5cce 177#if !defined(DISABLE_EBS_PROTECTION)
cbef697a
PJ
178 /* we need to hook ExitBootServices() so a) we can enforce the policy
179 * and b) we can unwrap when we're done. */
180 system_exit_boot_services = systab->BootServices->ExitBootServices;
181 systab->BootServices->ExitBootServices = exit_boot_services;
031e5cce 182#endif /* defined(DISABLE_EBS_PROTECTION) */
d3819813
MTL
183}
184
185void
186unhook_exit(void)
187{
188 systab->BootServices->Exit = system_exit;
8529e0f7 189 BS = systab->BootServices;
d3819813
MTL
190}
191
192void
193hook_exit(EFI_SYSTEM_TABLE *local_systab)
194{
195 systab = local_systab;
8529e0f7 196 BS = local_systab->BootServices;
cbef697a
PJ
197
198 /* we need to hook Exit() so that we can allow users to quit the
199 * bootloader and still e.g. start a new one or run an internal
200 * shell. */
201 system_exit = systab->BootServices->Exit;
1042fd7c 202 systab->BootServices->Exit = do_exit;
cbef697a 203}