189 lines
8.9 KiB
Diff
189 lines
8.9 KiB
Diff
|
From 8d0b70887a09b9d4a8b669620579d3b6780f0755 Mon Sep 17 00:00:00 2001
|
||
|
From: Jan Janssen <medhefgo@web.de>
|
||
|
Date: Tue, 15 Nov 2022 18:53:02 +0100
|
||
|
Subject: [PATCH] boot: Replace firmware security hooks directly
|
||
|
|
||
|
For some firmware, replacing their own security arch instance with our
|
||
|
override using ReinstallProtocolInterface() is not enough as they will
|
||
|
not use it. This commit goes back to how this was done before by
|
||
|
directly modifying the security protocols.
|
||
|
|
||
|
Fixes: #25336
|
||
|
(cherry picked from commit 967a868563996e928f1fade5bcafc82a7219742b)
|
||
|
|
||
|
Related: #2138081
|
||
|
---
|
||
|
src/boot/efi/secure-boot.c | 119 +++++++++++++------------------------
|
||
|
1 file changed, 40 insertions(+), 79 deletions(-)
|
||
|
|
||
|
diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c
|
||
|
index 0e615c55e0..65457bf423 100644
|
||
|
--- a/src/boot/efi/secure-boot.c
|
||
|
+++ b/src/boot/efi/secure-boot.c
|
||
|
@@ -128,15 +128,10 @@ out_deallocate:
|
||
|
}
|
||
|
|
||
|
static struct SecurityOverride {
|
||
|
- /* Our own security arch instances that we register onto original_handle, thereby replacing the
|
||
|
- * firmware provided instances. */
|
||
|
- EFI_SECURITY_ARCH_PROTOCOL override;
|
||
|
- EFI_SECURITY2_ARCH_PROTOCOL override2;
|
||
|
-
|
||
|
- /* These are saved so we can uninstall our own instance later. */
|
||
|
- EFI_HANDLE original_handle, original_handle2;
|
||
|
- EFI_SECURITY_ARCH_PROTOCOL *original_security;
|
||
|
- EFI_SECURITY2_ARCH_PROTOCOL *original_security2;
|
||
|
+ EFI_SECURITY_ARCH_PROTOCOL *security;
|
||
|
+ EFI_SECURITY2_ARCH_PROTOCOL *security2;
|
||
|
+ EFI_SECURITY_FILE_AUTHENTICATION_STATE original_hook;
|
||
|
+ EFI_SECURITY2_FILE_AUTHENTICATION original_hook2;
|
||
|
|
||
|
security_validator_t validator;
|
||
|
const void *validator_ctx;
|
||
|
@@ -148,13 +143,13 @@ static EFIAPI EFI_STATUS security_hook(
|
||
|
const EFI_DEVICE_PATH *file) {
|
||
|
|
||
|
assert(security_override.validator);
|
||
|
- assert(security_override.original_security);
|
||
|
+ assert(security_override.security);
|
||
|
+ assert(security_override.original_hook);
|
||
|
|
||
|
if (security_override.validator(security_override.validator_ctx, file, NULL, 0))
|
||
|
return EFI_SUCCESS;
|
||
|
|
||
|
- return security_override.original_security->FileAuthenticationState(
|
||
|
- security_override.original_security, authentication_status, file);
|
||
|
+ return security_override.original_hook(security_override.security, authentication_status, file);
|
||
|
}
|
||
|
|
||
|
static EFIAPI EFI_STATUS security2_hook(
|
||
|
@@ -165,92 +160,58 @@ static EFIAPI EFI_STATUS security2_hook(
|
||
|
BOOLEAN boot_policy) {
|
||
|
|
||
|
assert(security_override.validator);
|
||
|
- assert(security_override.original_security2);
|
||
|
+ assert(security_override.security2);
|
||
|
+ assert(security_override.original_hook2);
|
||
|
|
||
|
if (security_override.validator(security_override.validator_ctx, device_path, file_buffer, file_size))
|
||
|
return EFI_SUCCESS;
|
||
|
|
||
|
- return security_override.original_security2->FileAuthentication(
|
||
|
- security_override.original_security2, device_path, file_buffer, file_size, boot_policy);
|
||
|
+ return security_override.original_hook2(
|
||
|
+ security_override.security2, device_path, file_buffer, file_size, boot_policy);
|
||
|
}
|
||
|
|
||
|
-static EFI_STATUS install_security_override_one(
|
||
|
- EFI_GUID guid, void *override, EFI_HANDLE *ret_original_handle, void **ret_original_security) {
|
||
|
+/* This replaces the platform provided security arch protocols hooks (defined in the UEFI Platform
|
||
|
+ * Initialization Specification) with our own that uses the given validator to decide if a image is to be
|
||
|
+ * trusted. If not running in secure boot or the protocols are not available nothing happens. The override
|
||
|
+ * must be removed with uninstall_security_override() after LoadImage() has been called.
|
||
|
+ *
|
||
|
+ * This is a hack as we do not own the security protocol instances and modifying them is not an official part
|
||
|
+ * of their spec. But there is little else we can do to circumvent secure boot short of implementing our own
|
||
|
+ * PE loader. We could replace the firmware instances with our own instance using
|
||
|
+ * ReinstallProtocolInterface(), but some firmware will still use the old ones. */
|
||
|
+void install_security_override(security_validator_t validator, const void *validator_ctx) {
|
||
|
EFI_STATUS err;
|
||
|
|
||
|
- assert(override);
|
||
|
- assert(ret_original_handle);
|
||
|
- assert(ret_original_security);
|
||
|
-
|
||
|
- _cleanup_free_ EFI_HANDLE *handles = NULL;
|
||
|
- size_t n_handles = 0;
|
||
|
-
|
||
|
- err = BS->LocateHandleBuffer(ByProtocol, &guid, NULL, &n_handles, &handles);
|
||
|
- if (err != EFI_SUCCESS)
|
||
|
- /* No security arch protocol around? */
|
||
|
- return err;
|
||
|
-
|
||
|
- /* There should only ever be one security arch protocol instance, but let's be paranoid here. */
|
||
|
- assert(n_handles == 1);
|
||
|
-
|
||
|
- void *security = NULL;
|
||
|
- err = BS->LocateProtocol(&guid, NULL, &security);
|
||
|
- if (err != EFI_SUCCESS)
|
||
|
- return log_error_status_stall(err, u"Error getting security arch protocol: %r", err);
|
||
|
-
|
||
|
- err = BS->ReinstallProtocolInterface(handles[0], &guid, security, override);
|
||
|
- if (err != EFI_SUCCESS)
|
||
|
- return log_error_status_stall(err, u"Error overriding security arch protocol: %r", err);
|
||
|
-
|
||
|
- *ret_original_security = security;
|
||
|
- *ret_original_handle = handles[0];
|
||
|
- return EFI_SUCCESS;
|
||
|
-}
|
||
|
-
|
||
|
-/* This replaces the platform provided security arch protocols (defined in the UEFI Platform Initialization
|
||
|
- * Specification) with the provided override instances. If not running in secure boot or the protocols are
|
||
|
- * not available nothing happens. The override instances are provided with the necessary info to undo this
|
||
|
- * in uninstall_security_override(). */
|
||
|
-void install_security_override(security_validator_t validator, const void *validator_ctx) {
|
||
|
assert(validator);
|
||
|
|
||
|
if (!secure_boot_enabled())
|
||
|
return;
|
||
|
|
||
|
security_override = (struct SecurityOverride) {
|
||
|
- { .FileAuthenticationState = security_hook, },
|
||
|
- { .FileAuthentication = security2_hook, },
|
||
|
.validator = validator,
|
||
|
.validator_ctx = validator_ctx,
|
||
|
};
|
||
|
|
||
|
- (void) install_security_override_one(
|
||
|
- (EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID,
|
||
|
- &security_override.override,
|
||
|
- &security_override.original_handle,
|
||
|
- (void **) &security_override.original_security);
|
||
|
- (void) install_security_override_one(
|
||
|
- (EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID,
|
||
|
- &security_override.override2,
|
||
|
- &security_override.original_handle2,
|
||
|
- (void **) &security_override.original_security2);
|
||
|
+ EFI_SECURITY_ARCH_PROTOCOL *security = NULL;
|
||
|
+ err = BS->LocateProtocol(&(EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID, NULL, (void **) &security);
|
||
|
+ if (err == EFI_SUCCESS) {
|
||
|
+ security_override.security = security;
|
||
|
+ security_override.original_hook = security->FileAuthenticationState;
|
||
|
+ security->FileAuthenticationState = security_hook;
|
||
|
+ }
|
||
|
+
|
||
|
+ EFI_SECURITY2_ARCH_PROTOCOL *security2 = NULL;
|
||
|
+ err = BS->LocateProtocol(&(EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID, NULL, (void **) &security2);
|
||
|
+ if (err == EFI_SUCCESS) {
|
||
|
+ security_override.security2 = security2;
|
||
|
+ security_override.original_hook2 = security2->FileAuthentication;
|
||
|
+ security2->FileAuthentication = security2_hook;
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
void uninstall_security_override(void) {
|
||
|
- /* We use assert_se here to guarantee the system is not in a weird state in the unlikely case of an
|
||
|
- * error restoring the original protocols. */
|
||
|
-
|
||
|
- if (security_override.original_handle)
|
||
|
- assert_se(BS->ReinstallProtocolInterface(
|
||
|
- security_override.original_handle,
|
||
|
- &(EFI_GUID) EFI_SECURITY_ARCH_PROTOCOL_GUID,
|
||
|
- &security_override.override,
|
||
|
- security_override.original_security) == EFI_SUCCESS);
|
||
|
-
|
||
|
- if (security_override.original_handle2)
|
||
|
- assert_se(BS->ReinstallProtocolInterface(
|
||
|
- security_override.original_handle2,
|
||
|
- &(EFI_GUID) EFI_SECURITY2_ARCH_PROTOCOL_GUID,
|
||
|
- &security_override.override2,
|
||
|
- security_override.original_security2) == EFI_SUCCESS);
|
||
|
+ if (security_override.original_hook)
|
||
|
+ security_override.security->FileAuthenticationState = security_override.original_hook;
|
||
|
+ if (security_override.original_hook2)
|
||
|
+ security_override.security2->FileAuthentication = security_override.original_hook2;
|
||
|
}
|
||
|
--
|
||
|
2.38.1
|
||
|
|