]> git.proxmox.com Git - efi-boot-shim.git/blob - replacements.c
Switch to using gcc-12
[efi-boot-shim.git] / replacements.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 /*
3 * shim - trivial UEFI first-stage bootloader
4 *
5 * Copyright Red Hat, Inc
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 */
21 #include "shim.h"
22
23 static EFI_SYSTEM_TABLE *systab;
24
25 EFI_SYSTEM_TABLE *
26 get_active_systab(void)
27 {
28 if (systab)
29 return systab;
30 return ST;
31 }
32
33 static typeof(systab->BootServices->LoadImage) system_load_image;
34 static typeof(systab->BootServices->StartImage) system_start_image;
35 static typeof(systab->BootServices->Exit) system_exit;
36 #if !defined(DISABLE_EBS_PROTECTION)
37 static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
38 #endif /* !defined(DISABLE_EBS_PROTECTION) */
39
40 static EFI_HANDLE last_loaded_image;
41
42 void
43 unhook_system_services(void)
44 {
45 if (!systab)
46 return;
47
48 systab->BootServices->LoadImage = system_load_image;
49 systab->BootServices->StartImage = system_start_image;
50 #if !defined(DISABLE_EBS_PROTECTION)
51 systab->BootServices->ExitBootServices = system_exit_boot_services;
52 #endif /* !defined(DISABLE_EBS_PROTECTION) */
53 BS = systab->BootServices;
54 }
55
56 static EFI_STATUS EFIAPI
57 load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
58 EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer,
59 UINTN SourceSize, EFI_HANDLE *ImageHandle)
60 {
61 EFI_STATUS efi_status;
62
63 unhook_system_services();
64 efi_status = BS->LoadImage(BootPolicy, ParentImageHandle, DevicePath,
65 SourceBuffer, SourceSize, ImageHandle);
66 hook_system_services(systab);
67 if (EFI_ERROR(efi_status))
68 last_loaded_image = NULL;
69 else
70 last_loaded_image = *ImageHandle;
71 return efi_status;
72 }
73
74 static EFI_STATUS EFIAPI
75 replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
76 {
77 EFI_STATUS efi_status;
78 unhook_system_services();
79
80 if (image_handle == last_loaded_image) {
81 loader_is_participating = 1;
82 uninstall_shim_protocols();
83 }
84 efi_status = BS->StartImage(image_handle, exit_data_size, exit_data);
85 if (EFI_ERROR(efi_status)) {
86 if (image_handle == last_loaded_image) {
87 EFI_STATUS efi_status2 = install_shim_protocols();
88
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");
93 msleep(5000000);
94 RT->ResetSystem(EfiResetShutdown,
95 EFI_SECURITY_VIOLATION,
96 0, NULL);
97 }
98 }
99 hook_system_services(systab);
100 loader_is_participating = 0;
101 }
102 return efi_status;
103 }
104
105 #if !defined(DISABLE_EBS_PROTECTION)
106 static EFI_STATUS EFIAPI
107 exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
108 {
109 if (loader_is_participating ||
110 verification_method == VERIFIED_BY_HASH) {
111 unhook_system_services();
112 EFI_STATUS efi_status;
113 efi_status = BS->ExitBootServices(image_key, map_key);
114 if (EFI_ERROR(efi_status))
115 hook_system_services(systab);
116 return efi_status;
117 }
118
119 console_print(L"Bootloader has not verified loaded image.\n");
120 console_print(L"System is compromised. halting.\n");
121 msleep(5000000);
122 RT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL);
123 return EFI_SECURITY_VIOLATION;
124 }
125 #endif /* !defined(DISABLE_EBS_PROTECTION) */
126
127 static EFI_STATUS EFIAPI
128 do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
129 UINTN ExitDataSize, CHAR16 *ExitData)
130 {
131 EFI_STATUS efi_status;
132
133 shim_fini();
134
135 restore_loaded_image();
136
137 efi_status = BS->Exit(ImageHandle, ExitStatus,
138 ExitDataSize, ExitData);
139 if (EFI_ERROR(efi_status)) {
140 EFI_STATUS efi_status2 = shim_init();
141
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");
146 msleep(5000000);
147 RT->ResetSystem(EfiResetShutdown,
148 EFI_SECURITY_VIOLATION, 0, NULL);
149 }
150 }
151 return efi_status;
152 }
153
154 void
155 hook_system_services(EFI_SYSTEM_TABLE *local_systab)
156 {
157 systab = local_systab;
158 BS = systab->BootServices;
159
160 /* We need to hook various calls to make this work... */
161
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
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
168 * through BDS gives us. */
169 system_load_image = systab->BootServices->LoadImage;
170 systab->BootServices->LoadImage = load_image;
171
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;
175 systab->BootServices->StartImage = replacement_start_image;
176
177 #if !defined(DISABLE_EBS_PROTECTION)
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;
182 #endif /* defined(DISABLE_EBS_PROTECTION) */
183 }
184
185 void
186 unhook_exit(void)
187 {
188 systab->BootServices->Exit = system_exit;
189 BS = systab->BootServices;
190 }
191
192 void
193 hook_exit(EFI_SYSTEM_TABLE *local_systab)
194 {
195 systab = local_systab;
196 BS = local_systab->BootServices;
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;
202 systab->BootServices->Exit = do_exit;
203 }