arrfab / rpms / shim

Forked from rpms/shim 5 years ago
Clone

Blame SOURCES/0003-Allow-fallback-to-use-the-system-s-LoadImage-StartIm.patch

f2fa6b
From 06495f692fa748a553ffbde8bfae2974d8c791c0 Mon Sep 17 00:00:00 2001
f2fa6b
From: Peter Jones <pjones@redhat.com>
f2fa6b
Date: Fri, 14 Feb 2014 15:38:25 -0500
f2fa6b
Subject: [PATCH 3/3] Allow fallback to use the system's LoadImage/StartImage .
f2fa6b
f2fa6b
Track use of the system's LoadImage(), and when the next StartImage()
f2fa6b
call is for an image the system verified, allow that to count as
f2fa6b
participating, since it has been verified by the system's db.
f2fa6b
f2fa6b
Signed-off-by: Peter Jones <pjones@redhat.com>
f2fa6b
---
f2fa6b
 replacements.c | 68 +++++++++++++++++++++++++++++++++++++++++++++-
f2fa6b
 replacements.h |  3 +++
f2fa6b
 shim.c         | 85 +++++++++++++++++++++++++++++++++++-----------------------
f2fa6b
 3 files changed, 121 insertions(+), 35 deletions(-)
f2fa6b
f2fa6b
diff --git a/replacements.c b/replacements.c
f2fa6b
index 5ea5c32..48dc437 100644
f2fa6b
--- a/replacements.c
f2fa6b
+++ b/replacements.c
f2fa6b
@@ -60,26 +60,82 @@
f2fa6b
 
f2fa6b
 static EFI_SYSTEM_TABLE *systab;
f2fa6b
 
f2fa6b
+static typeof(systab->BootServices->LoadImage) system_load_image;
f2fa6b
 static typeof(systab->BootServices->StartImage) system_start_image;
f2fa6b
 static typeof(systab->BootServices->Exit) system_exit;
f2fa6b
 static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;
f2fa6b
 
f2fa6b
+static EFI_HANDLE last_loaded_image;
f2fa6b
+
f2fa6b
 void
f2fa6b
 unhook_system_services(void)
f2fa6b
 {
f2fa6b
 	systab->BootServices->Exit = system_exit;
f2fa6b
+	systab->BootServices->LoadImage = system_load_image;
f2fa6b
 	systab->BootServices->StartImage = system_start_image;
f2fa6b
 	systab->BootServices->ExitBootServices = system_exit_boot_services;
f2fa6b
 }
f2fa6b
 
f2fa6b
 static EFI_STATUS EFIAPI
f2fa6b
+load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
f2fa6b
+	EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer,
f2fa6b
+	UINTN SourceSize, EFI_HANDLE *ImageHandle)
f2fa6b
+{
f2fa6b
+	EFI_STATUS status;
f2fa6b
+	unhook_system_services();
f2fa6b
+
f2fa6b
+	status = systab->BootServices->LoadImage(BootPolicy,
f2fa6b
+			ParentImageHandle, DevicePath,
f2fa6b
+			SourceBuffer, SourceSize, ImageHandle);
f2fa6b
+	hook_system_services(systab);
f2fa6b
+	if (EFI_ERROR(status))
f2fa6b
+		last_loaded_image = NULL;
f2fa6b
+	else
f2fa6b
+		last_loaded_image = *ImageHandle;
f2fa6b
+	return status;
f2fa6b
+}
f2fa6b
+
f2fa6b
+static EFI_STATUS EFIAPI
f2fa6b
 start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
f2fa6b
 {
f2fa6b
 	EFI_STATUS status;
f2fa6b
 	unhook_system_services();
f2fa6b
+
f2fa6b
+	/* We have to uninstall shim's protocol here, because if we're
f2fa6b
+	 * On the fallback.efi path, then our call pathway is:
f2fa6b
+	 *
f2fa6b
+	 * shim->fallback->shim->grub
f2fa6b
+	 * ^               ^      ^
f2fa6b
+	 * |               |      \- gets protocol #0
f2fa6b
+	 * |               \- installs its protocol (#1)
f2fa6b
+	 * \- installs its protocol (#0)
f2fa6b
+	 * and if we haven't removed this, then grub will get the *first*
f2fa6b
+	 * shim's protocol, but it'll get the second shim's systab
f2fa6b
+	 * replacements.  So even though it will participate and verify
f2fa6b
+	 * the kernel, the systab never finds out.
f2fa6b
+	 */
f2fa6b
+	if (image_handle == last_loaded_image) {
f2fa6b
+		loader_is_participating = 1;
f2fa6b
+		uninstall_shim_protocols();
f2fa6b
+	}
f2fa6b
 	status = systab->BootServices->StartImage(image_handle, exit_data_size, exit_data);
f2fa6b
-	if (EFI_ERROR(status))
f2fa6b
+	if (EFI_ERROR(status)) {
f2fa6b
+		if (image_handle == last_loaded_image) {
f2fa6b
+			EFI_STATUS status2 = install_shim_protocols();
f2fa6b
+
f2fa6b
+			if (EFI_ERROR(status2)) {
f2fa6b
+				Print(L"Something has gone seriously wrong: %d\n",
f2fa6b
+					status2);
f2fa6b
+				Print(L"shim cannot continue, sorry.\n");
f2fa6b
+				systab->BootServices->Stall(5000000);
f2fa6b
+				systab->RuntimeServices->ResetSystem(
f2fa6b
+					EfiResetShutdown,
f2fa6b
+					EFI_SECURITY_VIOLATION, 0, NULL);
f2fa6b
+			}
f2fa6b
+		}
f2fa6b
 		hook_system_services(systab);
f2fa6b
+		loader_is_participating = 0;
f2fa6b
+	}
f2fa6b
 	return status;
f2fa6b
 }
f2fa6b
 
f2fa6b
@@ -123,6 +179,16 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)
f2fa6b
 
f2fa6b
 	/* We need to hook various calls to make this work... */
f2fa6b
 
f2fa6b
+	/* We need LoadImage() hooked so that fallback.c can load shim
f2fa6b
+	 * without having to fake LoadImage as well.  This allows it
f2fa6b
+	 * to call the system LoadImage(), and have us track the output
f2fa6b
+	 * and mark loader_is_participating in start_image.  This means
f2fa6b
+	 * anything added by fallback has to be verified by the system db,
f2fa6b
+	 * which we want to preserve anyway, since that's all launching
f2fa6b
+	 * through BDS gives us. */
f2fa6b
+	system_load_image = systab->BootServices->LoadImage;
f2fa6b
+	systab->BootServices->LoadImage = load_image;
f2fa6b
+
f2fa6b
 	/* we need StartImage() so that we can allow chain booting to an
f2fa6b
 	 * image trusted by the firmware */
f2fa6b
 	system_start_image = systab->BootServices->StartImage;
f2fa6b
diff --git a/replacements.h b/replacements.h
f2fa6b
index 5b57bc2..bd09424 100644
f2fa6b
--- a/replacements.h
f2fa6b
+++ b/replacements.h
f2fa6b
@@ -41,4 +41,7 @@ extern int loader_is_participating;
f2fa6b
 extern void hook_system_services(EFI_SYSTEM_TABLE *local_systab);
f2fa6b
 extern void unhook_system_services(void);
f2fa6b
 
f2fa6b
+extern EFI_STATUS install_shim_protocols(void);
f2fa6b
+extern void uninstall_shim_protocols(void);
f2fa6b
+
f2fa6b
 #endif /* SHIM_REPLACEMENTS_H */
f2fa6b
diff --git a/shim.c b/shim.c
f2fa6b
index cf93d65..0e18d38 100644
f2fa6b
--- a/shim.c
f2fa6b
+++ b/shim.c
f2fa6b
@@ -1707,11 +1707,56 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
f2fa6b
 	return EFI_SUCCESS;
f2fa6b
 }
f2fa6b
 
f2fa6b
-EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
f2fa6b
+static SHIM_LOCK shim_lock_interface;
f2fa6b
+static EFI_HANDLE shim_lock_handle;
f2fa6b
+
f2fa6b
+EFI_STATUS
f2fa6b
+install_shim_protocols(void)
f2fa6b
+{
f2fa6b
+	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
f2fa6b
+	EFI_STATUS efi_status;
f2fa6b
+	/*
f2fa6b
+	 * Install the protocol
f2fa6b
+	 */
f2fa6b
+	efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
f2fa6b
+			  &shim_lock_handle, &shim_lock_guid,
f2fa6b
+			  EFI_NATIVE_INTERFACE, &shim_lock_interface);
f2fa6b
+	if (EFI_ERROR(efi_status)) {
f2fa6b
+		console_error(L"Could not install security protocol",
f2fa6b
+			      efi_status);
f2fa6b
+		return efi_status;
f2fa6b
+	}
f2fa6b
+
f2fa6b
+#if defined(OVERRIDE_SECURITY_POLICY)
f2fa6b
+	/*
f2fa6b
+	 * Install the security protocol hook
f2fa6b
+	 */
f2fa6b
+	security_policy_install(shim_verify);
f2fa6b
+#endif
f2fa6b
+
f2fa6b
+	return EFI_SUCCESS;
f2fa6b
+}
f2fa6b
+
f2fa6b
+void
f2fa6b
+uninstall_shim_protocols(void)
f2fa6b
 {
f2fa6b
 	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
f2fa6b
-	static SHIM_LOCK shim_lock_interface;
f2fa6b
-	EFI_HANDLE handle = NULL;
f2fa6b
+#if defined(OVERRIDE_SECURITY_POLICY)
f2fa6b
+	/*
f2fa6b
+	 * Clean up the security protocol hook
f2fa6b
+	 */
f2fa6b
+	security_policy_uninstall();
f2fa6b
+#endif
f2fa6b
+
f2fa6b
+	/*
f2fa6b
+	 * If we're back here then clean everything up before exiting
f2fa6b
+	 */
f2fa6b
+	uefi_call_wrapper(BS->UninstallProtocolInterface, 3, shim_lock_handle,
f2fa6b
+			  &shim_lock_guid, &shim_lock_interface);
f2fa6b
+}
f2fa6b
+
f2fa6b
+EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
f2fa6b
+{
f2fa6b
 	EFI_STATUS efi_status;
f2fa6b
 
f2fa6b
 	verification_method = VERIFIED_BY_NOTHING;
f2fa6b
@@ -1768,24 +1813,9 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
f2fa6b
 		}
f2fa6b
 	}
f2fa6b
 
f2fa6b
-	/*
f2fa6b
-	 * Install the protocol
f2fa6b
-	 */
f2fa6b
-	efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
f2fa6b
-			  &handle, &shim_lock_guid, EFI_NATIVE_INTERFACE,
f2fa6b
-			  &shim_lock_interface);
f2fa6b
-	if (EFI_ERROR(efi_status)) {
f2fa6b
-		console_error(L"Could not install security protocol",
f2fa6b
-			      efi_status);
f2fa6b
+	efi_status = install_shim_protocols();
f2fa6b
+	if (EFI_ERROR(efi_status))
f2fa6b
 		return efi_status;
f2fa6b
-	}
f2fa6b
-
f2fa6b
-#if defined(OVERRIDE_SECURITY_POLICY)
f2fa6b
-	/*
f2fa6b
-	 * Install the security protocol hook
f2fa6b
-	 */
f2fa6b
-	security_policy_install(shim_verify);
f2fa6b
-#endif
f2fa6b
 
f2fa6b
 	/*
f2fa6b
 	 * Enter MokManager if necessary
f2fa6b
@@ -1810,20 +1840,7 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
f2fa6b
 
f2fa6b
 	efi_status = init_grub(image_handle);
f2fa6b
 
f2fa6b
-#if defined(OVERRIDE_SECURITY_POLICY)
f2fa6b
-	/*
f2fa6b
-	 * Clean up the security protocol hook
f2fa6b
-	 */
f2fa6b
-	security_policy_uninstall();
f2fa6b
-#endif
f2fa6b
-
f2fa6b
-	/*
f2fa6b
-	 * If we're back here then clean everything up before exiting
f2fa6b
-	 */
f2fa6b
-	uefi_call_wrapper(BS->UninstallProtocolInterface, 3, handle,
f2fa6b
-			  &shim_lock_guid, &shim_lock_interface);
f2fa6b
-
f2fa6b
-
f2fa6b
+	uninstall_shim_protocols();
f2fa6b
 	/*
f2fa6b
 	 * Remove our hooks from system services.
f2fa6b
 	 */
f2fa6b
-- 
f2fa6b
1.8.5.3
f2fa6b