1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * shim - trivial UEFI first-stage bootloader
5 * Copyright Red Hat, Inc
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,
23 static EFI_SYSTEM_TABLE
*systab
;
26 get_active_systab(void)
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) */
40 static EFI_HANDLE last_loaded_image
;
43 unhook_system_services(void)
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
;
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
)
61 EFI_STATUS efi_status
;
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
;
70 last_loaded_image
= *ImageHandle
;
74 static EFI_STATUS EFIAPI
75 replacement_start_image(EFI_HANDLE image_handle
, UINTN
*exit_data_size
, CHAR16
**exit_data
)
77 EFI_STATUS efi_status
;
78 unhook_system_services();
80 if (image_handle
== last_loaded_image
) {
81 loader_is_participating
= 1;
82 uninstall_shim_protocols();
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();
89 if (EFI_ERROR(efi_status2
)) {
90 console_print(L
"Something has gone seriously wrong: %r\n",
92 console_print(L
"shim cannot continue, sorry.\n");
94 RT
->ResetSystem(EfiResetShutdown
,
95 EFI_SECURITY_VIOLATION
,
99 hook_system_services(systab
);
100 loader_is_participating
= 0;
105 #if !defined(DISABLE_EBS_PROTECTION)
106 static EFI_STATUS EFIAPI
107 exit_boot_services(EFI_HANDLE image_key
, UINTN map_key
)
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
);
119 console_print(L
"Bootloader has not verified loaded image.\n");
120 console_print(L
"System is compromised. halting.\n");
122 RT
->ResetSystem(EfiResetShutdown
, EFI_SECURITY_VIOLATION
, 0, NULL
);
123 return EFI_SECURITY_VIOLATION
;
125 #endif /* !defined(DISABLE_EBS_PROTECTION) */
127 static EFI_STATUS EFIAPI
128 do_exit(EFI_HANDLE ImageHandle
, EFI_STATUS ExitStatus
,
129 UINTN ExitDataSize
, CHAR16
*ExitData
)
131 EFI_STATUS efi_status
;
135 restore_loaded_image();
137 efi_status
= BS
->Exit(ImageHandle
, ExitStatus
,
138 ExitDataSize
, ExitData
);
139 if (EFI_ERROR(efi_status
)) {
140 EFI_STATUS efi_status2
= shim_init();
142 if (EFI_ERROR(efi_status2
)) {
143 console_print(L
"Something has gone seriously wrong: %r\n",
145 console_print(L
"shim cannot continue, sorry.\n");
147 RT
->ResetSystem(EfiResetShutdown
,
148 EFI_SECURITY_VIOLATION
, 0, NULL
);
155 hook_system_services(EFI_SYSTEM_TABLE
*local_systab
)
157 systab
= local_systab
;
158 BS
= systab
->BootServices
;
160 /* We need to hook various calls to make this work... */
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
;
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
;
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) */
188 systab
->BootServices
->Exit
= system_exit
;
189 BS
= systab
->BootServices
;
193 hook_exit(EFI_SYSTEM_TABLE
*local_systab
)
195 systab
= local_systab
;
196 BS
= local_systab
->BootServices
;
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
201 system_exit
= systab
->BootServices
->Exit
;
202 systab
->BootServices
->Exit
= do_exit
;