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

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