arrfab / rpms / shim

Forked from rpms/shim 4 years ago
Clone
Blob Blame History Raw
From 06495f692fa748a553ffbde8bfae2974d8c791c0 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Fri, 14 Feb 2014 15:38:25 -0500
Subject: [PATCH 22/74] Allow fallback to use the system's LoadImage/StartImage
 .

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 | 68 +++++++++++++++++++++++++++++++++++++++++++++-
 replacements.h |  3 +++
 shim.c         | 85 +++++++++++++++++++++++++++++++++++-----------------------
 3 files changed, 121 insertions(+), 35 deletions(-)

diff --git a/replacements.c b/replacements.c
index 5ea5c32..48dc437 100644
--- a/replacements.c
+++ b/replacements.c
@@ -60,26 +60,82 @@
 
 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;
diff --git a/replacements.h b/replacements.h
index 5b57bc2..bd09424 100644
--- a/replacements.h
+++ b/replacements.h
@@ -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 cf93d65..0e18d38 100644
--- 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.
 	 */
-- 
1.9.3