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