]>
Commit | Line | Data |
---|---|---|
cbef697a PJ |
1 | /* |
2 | * shim - trivial UEFI first-stage bootloader | |
3 | * | |
4 | * Copyright 2012 Red Hat, Inc <mjg@redhat.com> | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * | |
10 | * Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * | |
13 | * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * | |
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
21 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
22 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
23 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
24 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
27 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
29 | * OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | * | |
31 | * Significant portions of this code are derived from Tianocore | |
32 | * (http://tianocore.sf.net) and are Copyright 2009-2012 Intel | |
33 | * Corporation. | |
34 | */ | |
35 | ||
36 | /* Chemical agents lend themselves to covert use in sabotage against | |
37 | * which it is exceedingly difficult to visualize any really effective | |
38 | * defense... I will not dwell upon this use of CBW because, as one | |
39 | * pursues the possibilities of such covert uses, one discovers that the | |
40 | * scenarios resemble that in which the components of a nuclear weapon | |
41 | * are smuggled into New York City and assembled in the basement of the | |
42 | * Empire State Building. | |
43 | * In other words, once the possibility is recognized to exist, about | |
44 | * all that one can do is worry about it. | |
45 | * -- Dr. Ivan L Bennett, Jr., testifying before the Subcommittee on | |
46 | * National Security Policy and Scientific Developments, November 20, | |
47 | * 1969. | |
48 | */ | |
49 | ||
50 | #include <efi.h> | |
51 | #include <efiapi.h> | |
52 | #include <efilib.h> | |
f892ac66 | 53 | |
cbef697a | 54 | #include "shim.h" |
cbef697a PJ |
55 | |
56 | static EFI_SYSTEM_TABLE *systab; | |
57 | ||
f892ac66 MTL |
58 | EFI_SYSTEM_TABLE * |
59 | get_active_systab(void) | |
60 | { | |
61 | if (systab) | |
62 | return systab; | |
63 | return ST; | |
64 | } | |
65 | ||
cf90edff | 66 | static typeof(systab->BootServices->LoadImage) system_load_image; |
cbef697a PJ |
67 | static typeof(systab->BootServices->StartImage) system_start_image; |
68 | static typeof(systab->BootServices->Exit) system_exit; | |
69 | static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services; | |
70 | ||
cf90edff PJ |
71 | static EFI_HANDLE last_loaded_image; |
72 | ||
98a99578 | 73 | void |
cbef697a PJ |
74 | unhook_system_services(void) |
75 | { | |
277127d1 AB |
76 | if (!systab) |
77 | return; | |
78 | ||
cf90edff | 79 | systab->BootServices->LoadImage = system_load_image; |
cbef697a PJ |
80 | systab->BootServices->StartImage = system_start_image; |
81 | systab->BootServices->ExitBootServices = system_exit_boot_services; | |
f892ac66 | 82 | gBS = systab->BootServices; |
cbef697a PJ |
83 | } |
84 | ||
cf90edff PJ |
85 | static EFI_STATUS EFIAPI |
86 | load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle, | |
87 | EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer, | |
88 | UINTN SourceSize, EFI_HANDLE *ImageHandle) | |
89 | { | |
f892ac66 | 90 | EFI_STATUS efi_status; |
cf90edff | 91 | |
f892ac66 MTL |
92 | unhook_system_services(); |
93 | efi_status = gBS->LoadImage(BootPolicy, ParentImageHandle, DevicePath, | |
94 | SourceBuffer, SourceSize, ImageHandle); | |
cf90edff | 95 | hook_system_services(systab); |
f892ac66 | 96 | if (EFI_ERROR(efi_status)) |
cf90edff PJ |
97 | last_loaded_image = NULL; |
98 | else | |
99 | last_loaded_image = *ImageHandle; | |
f892ac66 | 100 | return efi_status; |
cf90edff PJ |
101 | } |
102 | ||
cbef697a | 103 | static EFI_STATUS EFIAPI |
f892ac66 | 104 | replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data) |
cbef697a | 105 | { |
f892ac66 | 106 | EFI_STATUS efi_status; |
cbef697a | 107 | unhook_system_services(); |
cf90edff | 108 | |
cf90edff PJ |
109 | if (image_handle == last_loaded_image) { |
110 | loader_is_participating = 1; | |
111 | uninstall_shim_protocols(); | |
112 | } | |
f892ac66 MTL |
113 | efi_status = gBS->StartImage(image_handle, exit_data_size, exit_data); |
114 | if (EFI_ERROR(efi_status)) { | |
cf90edff | 115 | if (image_handle == last_loaded_image) { |
f892ac66 | 116 | EFI_STATUS efi_status2 = install_shim_protocols(); |
cf90edff | 117 | |
f892ac66 MTL |
118 | if (EFI_ERROR(efi_status2)) { |
119 | console_print(L"Something has gone seriously wrong: %r\n", | |
120 | efi_status2); | |
121 | console_print(L"shim cannot continue, sorry.\n"); | |
b6f94dbe | 122 | msleep(5000000); |
f892ac66 MTL |
123 | gRT->ResetSystem(EfiResetShutdown, |
124 | EFI_SECURITY_VIOLATION, | |
125 | 0, NULL); | |
cf90edff PJ |
126 | } |
127 | } | |
cbef697a | 128 | hook_system_services(systab); |
cf90edff PJ |
129 | loader_is_participating = 0; |
130 | } | |
f892ac66 | 131 | return efi_status; |
cbef697a PJ |
132 | } |
133 | ||
134 | static EFI_STATUS EFIAPI | |
135 | exit_boot_services(EFI_HANDLE image_key, UINTN map_key) | |
136 | { | |
f892ac66 MTL |
137 | if (loader_is_participating || |
138 | verification_method == VERIFIED_BY_HASH) { | |
cbef697a | 139 | unhook_system_services(); |
f892ac66 MTL |
140 | EFI_STATUS efi_status; |
141 | efi_status = gBS->ExitBootServices(image_key, map_key); | |
142 | if (EFI_ERROR(efi_status)) | |
cbef697a | 143 | hook_system_services(systab); |
f892ac66 | 144 | return efi_status; |
cbef697a PJ |
145 | } |
146 | ||
f892ac66 MTL |
147 | console_print(L"Bootloader has not verified loaded image.\n"); |
148 | console_print(L"System is compromised. halting.\n"); | |
b6f94dbe | 149 | msleep(5000000); |
f892ac66 | 150 | gRT->ResetSystem(EfiResetShutdown, EFI_SECURITY_VIOLATION, 0, NULL); |
cbef697a PJ |
151 | return EFI_SECURITY_VIOLATION; |
152 | } | |
153 | ||
154 | static EFI_STATUS EFIAPI | |
1042fd7c | 155 | do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus, |
d3819813 | 156 | UINTN ExitDataSize, CHAR16 *ExitData) |
cbef697a | 157 | { |
f892ac66 | 158 | EFI_STATUS efi_status; |
cbef697a | 159 | |
d3819813 MTL |
160 | shim_fini(); |
161 | ||
f892ac66 MTL |
162 | efi_status = gBS->Exit(ImageHandle, ExitStatus, |
163 | ExitDataSize, ExitData); | |
164 | if (EFI_ERROR(efi_status)) { | |
165 | EFI_STATUS efi_status2 = shim_init(); | |
d3819813 | 166 | |
f892ac66 MTL |
167 | if (EFI_ERROR(efi_status2)) { |
168 | console_print(L"Something has gone seriously wrong: %r\n", | |
169 | efi_status2); | |
170 | console_print(L"shim cannot continue, sorry.\n"); | |
b6f94dbe | 171 | msleep(5000000); |
f892ac66 MTL |
172 | gRT->ResetSystem(EfiResetShutdown, |
173 | EFI_SECURITY_VIOLATION, 0, NULL); | |
d3819813 MTL |
174 | } |
175 | } | |
f892ac66 | 176 | return efi_status; |
cbef697a PJ |
177 | } |
178 | ||
cbef697a PJ |
179 | void |
180 | hook_system_services(EFI_SYSTEM_TABLE *local_systab) | |
181 | { | |
cbef697a | 182 | systab = local_systab; |
f892ac66 | 183 | gBS = systab->BootServices; |
cbef697a PJ |
184 | |
185 | /* We need to hook various calls to make this work... */ | |
186 | ||
cf90edff PJ |
187 | /* We need LoadImage() hooked so that fallback.c can load shim |
188 | * without having to fake LoadImage as well. This allows it | |
189 | * to call the system LoadImage(), and have us track the output | |
f892ac66 MTL |
190 | * and mark loader_is_participating in replacement_start_image. This |
191 | * means anything added by fallback has to be verified by the system | |
192 | * db, which we want to preserve anyway, since that's all launching | |
cf90edff PJ |
193 | * through BDS gives us. */ |
194 | system_load_image = systab->BootServices->LoadImage; | |
195 | systab->BootServices->LoadImage = load_image; | |
196 | ||
cbef697a PJ |
197 | /* we need StartImage() so that we can allow chain booting to an |
198 | * image trusted by the firmware */ | |
199 | system_start_image = systab->BootServices->StartImage; | |
f892ac66 | 200 | systab->BootServices->StartImage = replacement_start_image; |
cbef697a PJ |
201 | |
202 | /* we need to hook ExitBootServices() so a) we can enforce the policy | |
203 | * and b) we can unwrap when we're done. */ | |
204 | system_exit_boot_services = systab->BootServices->ExitBootServices; | |
205 | systab->BootServices->ExitBootServices = exit_boot_services; | |
d3819813 MTL |
206 | } |
207 | ||
208 | void | |
209 | unhook_exit(void) | |
210 | { | |
211 | systab->BootServices->Exit = system_exit; | |
f892ac66 | 212 | gBS = systab->BootServices; |
d3819813 MTL |
213 | } |
214 | ||
215 | void | |
216 | hook_exit(EFI_SYSTEM_TABLE *local_systab) | |
217 | { | |
218 | systab = local_systab; | |
f892ac66 | 219 | gBS = local_systab->BootServices; |
cbef697a PJ |
220 | |
221 | /* we need to hook Exit() so that we can allow users to quit the | |
222 | * bootloader and still e.g. start a new one or run an internal | |
223 | * shell. */ | |
224 | system_exit = systab->BootServices->Exit; | |
1042fd7c | 225 | systab->BootServices->Exit = do_exit; |
cbef697a | 226 | } |