]>
Commit | Line | Data |
---|---|---|
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 | |
23 | static EFI_SYSTEM_TABLE *systab; | |
24 | ||
f892ac66 MTL |
25 | EFI_SYSTEM_TABLE * |
26 | get_active_systab(void) | |
27 | { | |
28 | if (systab) | |
29 | return systab; | |
30 | return ST; | |
31 | } | |
32 | ||
cf90edff | 33 | static typeof(systab->BootServices->LoadImage) system_load_image; |
cbef697a PJ |
34 | static typeof(systab->BootServices->StartImage) system_start_image; |
35 | static typeof(systab->BootServices->Exit) system_exit; | |
8529e0f7 | 36 | #if !defined(DISABLE_EBS_PROTECTION) |
cbef697a | 37 | static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services; |
8529e0f7 | 38 | #endif /* !defined(DISABLE_EBS_PROTECTION) */ |
cbef697a | 39 | |
cf90edff PJ |
40 | static EFI_HANDLE last_loaded_image; |
41 | ||
98a99578 | 42 | void |
cbef697a PJ |
43 | unhook_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 |
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 | { | |
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 | 74 | static EFI_STATUS EFIAPI |
f892ac66 | 75 | replacement_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 |
106 | static EFI_STATUS EFIAPI |
107 | exit_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 | |
127 | static EFI_STATUS EFIAPI | |
1042fd7c | 128 | do_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 |
154 | void |
155 | hook_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 | ||
185 | void | |
186 | unhook_exit(void) | |
187 | { | |
188 | systab->BootServices->Exit = system_exit; | |
8529e0f7 | 189 | BS = systab->BootServices; |
d3819813 MTL |
190 | } |
191 | ||
192 | void | |
193 | hook_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 | } |