summaryrefslogtreecommitdiff
path: root/replacements.c
diff options
context:
space:
mode:
Diffstat (limited to 'replacements.c')
-rw-r--r--replacements.c77
1 files changed, 70 insertions, 7 deletions
diff --git a/replacements.c b/replacements.c
index bac5e5d7..f7623d9d 100644
--- a/replacements.c
+++ b/replacements.c
@@ -60,30 +60,85 @@
static EFI_SYSTEM_TABLE *systab;
+static typeof(systab->BootServices->LoadImage) system_load_image;
static typeof(systab->BootServices->StartImage) system_start_image;
static typeof(systab->BootServices->Exit) system_exit;
static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
-extern UINT8 insecure_mode;
+static EFI_HANDLE last_loaded_image;
void
unhook_system_services(void)
{
- if (insecure_mode)
+ if (!systab)
return;
+
systab->BootServices->Exit = system_exit;
+ systab->BootServices->LoadImage = system_load_image;
systab->BootServices->StartImage = system_start_image;
systab->BootServices->ExitBootServices = system_exit_boot_services;
}
static EFI_STATUS EFIAPI
+load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
+ EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer,
+ UINTN SourceSize, EFI_HANDLE *ImageHandle)
+{
+ EFI_STATUS status;
+ unhook_system_services();
+
+ status = systab->BootServices->LoadImage(BootPolicy,
+ ParentImageHandle, DevicePath,
+ SourceBuffer, SourceSize, ImageHandle);
+ hook_system_services(systab);
+ if (EFI_ERROR(status))
+ last_loaded_image = NULL;
+ else
+ last_loaded_image = *ImageHandle;
+ return status;
+}
+
+static EFI_STATUS EFIAPI
start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
{
EFI_STATUS status;
unhook_system_services();
+
+ /* We have to uninstall shim's protocol here, because if we're
+ * On the fallback.efi path, then our call pathway is:
+ *
+ * shim->fallback->shim->grub
+ * ^ ^ ^
+ * | | \- gets protocol #0
+ * | \- installs its protocol (#1)
+ * \- installs its protocol (#0)
+ * and if we haven't removed this, then grub will get the *first*
+ * shim's protocol, but it'll get the second shim's systab
+ * replacements. So even though it will participate and verify
+ * the kernel, the systab never finds out.
+ */
+ if (image_handle == last_loaded_image) {
+ loader_is_participating = 1;
+ uninstall_shim_protocols();
+ }
status = systab->BootServices->StartImage(image_handle, exit_data_size, exit_data);
- if (EFI_ERROR(status))
+ if (EFI_ERROR(status)) {
+ if (image_handle == last_loaded_image) {
+ EFI_STATUS status2 = install_shim_protocols();
+
+ if (EFI_ERROR(status2)) {
+ Print(L"Something has gone seriously wrong: %d\n",
+ status2);
+ Print(L"shim cannot continue, sorry.\n");
+ systab->BootServices->Stall(5000000);
+ systab->RuntimeServices->ResetSystem(
+ EfiResetShutdown,
+ EFI_SECURITY_VIOLATION, 0, NULL);
+ }
+ }
hook_system_services(systab);
+ loader_is_participating = 0;
+ }
return status;
}
@@ -107,7 +162,7 @@ exit_boot_services(EFI_HANDLE image_key, UINTN map_key)
}
static EFI_STATUS EFIAPI
-exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
+do_exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
UINTN ExitDataSize, CHAR16 *ExitData)
{
EFI_STATUS status;
@@ -123,12 +178,20 @@ exit(EFI_HANDLE ImageHandle, EFI_STATUS ExitStatus,
void
hook_system_services(EFI_SYSTEM_TABLE *local_systab)
{
- if (insecure_mode)
- return;
systab = local_systab;
/* We need to hook various calls to make this work... */
+ /* We need LoadImage() hooked so that fallback.c can load shim
+ * without having to fake LoadImage as well. This allows it
+ * to call the system LoadImage(), and have us track the output
+ * and mark loader_is_participating in start_image. This means
+ * anything added by fallback has to be verified by the system db,
+ * which we want to preserve anyway, since that's all launching
+ * through BDS gives us. */
+ system_load_image = systab->BootServices->LoadImage;
+ systab->BootServices->LoadImage = load_image;
+
/* we need StartImage() so that we can allow chain booting to an
* image trusted by the firmware */
system_start_image = systab->BootServices->StartImage;
@@ -143,5 +206,5 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)
* bootloader and still e.g. start a new one or run an internal
* shell. */
system_exit = systab->BootServices->Exit;
- systab->BootServices->Exit = exit;
+ systab->BootServices->Exit = do_exit;
}