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;
+static EFI_HANDLE last_loaded_image;
+
void
unhook_system_services(void)
{
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;
}
/* 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;
return EFI_SUCCESS;
}
-EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
+static SHIM_LOCK shim_lock_interface;
+static EFI_HANDLE shim_lock_handle;
+
+EFI_STATUS
+install_shim_protocols(void)
+{
+ EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
+ EFI_STATUS efi_status;
+ /*
+ * Install the protocol
+ */
+ efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
+ &shim_lock_handle, &shim_lock_guid,
+ EFI_NATIVE_INTERFACE, &shim_lock_interface);
+ if (EFI_ERROR(efi_status)) {
+ console_error(L"Could not install security protocol",
+ efi_status);
+ return efi_status;
+ }
+
+#if defined(OVERRIDE_SECURITY_POLICY)
+ /*
+ * Install the security protocol hook
+ */
+ security_policy_install(shim_verify);
+#endif
+
+ return EFI_SUCCESS;
+}
+
+void
+uninstall_shim_protocols(void)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
- static SHIM_LOCK shim_lock_interface;
- EFI_HANDLE handle = NULL;
+#if defined(OVERRIDE_SECURITY_POLICY)
+ /*
+ * Clean up the security protocol hook
+ */
+ security_policy_uninstall();
+#endif
+
+ /*
+ * If we're back here then clean everything up before exiting
+ */
+ uefi_call_wrapper(BS->UninstallProtocolInterface, 3, shim_lock_handle,
+ &shim_lock_guid, &shim_lock_interface);
+}
+
+EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
+{
EFI_STATUS efi_status;
verification_method = VERIFIED_BY_NOTHING;
}
}
- /*
- * Install the protocol
- */
- efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
- &handle, &shim_lock_guid, EFI_NATIVE_INTERFACE,
- &shim_lock_interface);
- if (EFI_ERROR(efi_status)) {
- console_error(L"Could not install security protocol",
- efi_status);
+ efi_status = install_shim_protocols();
+ if (EFI_ERROR(efi_status))
return efi_status;
- }
-
-#if defined(OVERRIDE_SECURITY_POLICY)
- /*
- * Install the security protocol hook
- */
- security_policy_install(shim_verify);
-#endif
/*
* Enter MokManager if necessary
efi_status = init_grub(image_handle);
-#if defined(OVERRIDE_SECURITY_POLICY)
- /*
- * Clean up the security protocol hook
- */
- security_policy_uninstall();
-#endif
-
- /*
- * If we're back here then clean everything up before exiting
- */
- uefi_call_wrapper(BS->UninstallProtocolInterface, 3, handle,
- &shim_lock_guid, &shim_lock_interface);
-
-
+ uninstall_shim_protocols();
/*
* Remove our hooks from system services.
*/