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