]> git.proxmox.com Git - efi-boot-shim.git/commitdiff
Allow fallback to use the system's LoadImage/StartImage .
authorPeter Jones <pjones@redhat.com>
Fri, 14 Feb 2014 22:48:01 +0000 (17:48 -0500)
committerPeter Jones <pjones@redhat.com>
Fri, 14 Feb 2014 22:48:01 +0000 (17:48 -0500)
Track use of the system's LoadImage(), and when the next StartImage()
call is for an image the system verified, allow that to count as
participating, since it has been verified by the system's db.

Signed-off-by: Peter Jones <pjones@redhat.com>
replacements.c
replacements.h
shim.c

index 5ea5c3278c7a7e874cd292bce73386b515d8d39e..48dc43785e2d6a5c3684e1ee78870db10634efd0 100644 (file)
 
 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;
 }
 
@@ -123,6 +179,16 @@ hook_system_services(EFI_SYSTEM_TABLE *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;
index 5b57bc25d1b684915b49aae49176d426ab4152bd..bd0942404be4b5de3a7c8af7d448c091e161679d 100644 (file)
@@ -41,4 +41,7 @@ extern int loader_is_participating;
 extern void hook_system_services(EFI_SYSTEM_TABLE *local_systab);
 extern void unhook_system_services(void);
 
+extern EFI_STATUS install_shim_protocols(void);
+extern void uninstall_shim_protocols(void);
+
 #endif /* SHIM_REPLACEMENTS_H */
diff --git a/shim.c b/shim.c
index cf93d6540c932a467a43ac856ca6e82d1fe347dc..0e18d38712f9eb35c2a8734eaa6b9696d05431ab 100644 (file)
--- a/shim.c
+++ b/shim.c
@@ -1707,11 +1707,56 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
        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;
@@ -1768,24 +1813,9 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
                }
        }
 
-       /*
-        * 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
@@ -1810,20 +1840,7 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
 
        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.
         */