[PATCH 1/2] efi_loader: implement EFI Security Architecture protocols
Ian Mullins
imullins at redhat.com
Fri Jul 10 15:23:08 CEST 2026
From: Enric Balletbo i Serra <eballetbo at kernel.org>
This patch implements the EFI_SECURITY_ARCH_PROTOCOL and
EFI_SECURITY2_ARCH_PROTOCOL as defined in the UEFI Platform
Initialization (PI) specification.
These protocols provide a mechanism for the EFI loader to perform security
checks on images before they are executed. By default, the implementation
delegates to the internal UEFI Secure Boot authentication logic.
The primary motivation is to support EFI applications like systemd-stub
in Unified Kernel Images (UKI). These applications can install a custom
version of the security protocols to temporarily override authentication
for embedded payloads that were already verified as part of the signed
PE binary.
Signed-off-by: Enric Balletbo i Serra <eballetbo at kernel.org>
Signed-off-by: Ian Mullins <imullins at redhat.com>
---
include/efi_api.h | 30 ++++++++++++
include/efi_loader.h | 15 +++++-
lib/efi_loader/Kconfig | 11 +++++
lib/efi_loader/Makefile | 1 +
lib/efi_loader/efi_boottime.c | 3 +-
lib/efi_loader/efi_image_loader.c | 31 +++++++++---
lib/efi_loader/efi_security.c | 99 +++++++++++++++++++++++++++++++++++++++
lib/efi_loader/efi_setup.c | 7 +++
8 files changed, 188 insertions(+), 9 deletions(-)
diff --git a/include/efi_api.h b/include/efi_api.h
index d4fdd50c49e..1c52855af63 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -487,6 +487,14 @@ struct efi_runtime_services {
EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, \
0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
+#define EFI_SECURITY_ARCH_PROTOCOL_GUID \
+ EFI_GUID(0xa46423e3, 0x4617, 0x49f1, 0xb9, 0xff, \
+ 0xd1, 0xbf, 0xa9, 0x11, 0x58, 0x39)
+
+#define EFI_SECURITY2_ARCH_PROTOCOL_GUID \
+ EFI_GUID(0x94ab2f58, 0x1438, 0x4ef1, 0x91, 0x52, \
+ 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68)
+
/**
* struct efi_configuration_table - EFI Configuration Table
*
@@ -2445,4 +2453,26 @@ struct efi_disk {
void *buffer);
};
+struct efi_security_arch_protocol;
+
+typedef efi_status_t (EFIAPI *efi_security_file_authentication_state)(const struct efi_security_arch_protocol *this,
+ u32 authentication_status,
+ const struct efi_device_path *file);
+
+struct efi_security_arch_protocol {
+ efi_security_file_authentication_state file_authentication_state;
+};
+
+struct efi_security2_arch_protocol;
+
+typedef efi_status_t (EFIAPI *efi_security2_file_authentication)(const struct efi_security2_arch_protocol *this,
+ const struct efi_device_path *device_path,
+ void *file_buffer,
+ efi_uintn_t file_size,
+ bool boot_policy);
+
+struct efi_security2_arch_protocol {
+ efi_security2_file_authentication file_authentication;
+};
+
#endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3a4d502631c..b80ce390466 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -381,6 +381,9 @@ extern const efi_guid_t efi_guid_cert_type_pkcs7;
/* GUID of RNG protocol */
extern const efi_guid_t efi_guid_rng_protocol;
+/* GUIDs for EFI Security Architecture Protocols */
+extern const efi_guid_t efi_guid_security_arch_protocol;
+extern const efi_guid_t efi_guid_security2_arch_protocol;
/* GUID of capsule update result */
extern const efi_guid_t efi_guid_capsule_report;
/* GUID of firmware management protocol */
@@ -671,6 +674,12 @@ efi_status_t efi_console_register(void);
efi_status_t efi_disks_register(void);
/* Called by efi_init_obj_list() to install EFI_RNG_PROTOCOL */
efi_status_t efi_rng_register(void);
+/* Called by efi_init_obj_list() to install Security Architecture Protocols */
+efi_status_t efi_security_arch_register(void);
+/* Check image authentication via Security2 Architecture Protocol */
+efi_status_t efi_security_check_image(const struct efi_device_path *file_path,
+ void *file_buffer, efi_uintn_t file_size,
+ bool boot_policy);
/* Called by efi_init_obj_list() to install EFI_TCG2_PROTOCOL */
efi_status_t efi_tcg2_register(void);
/* Called by efi_init_obj_list() to install RISCV_EFI_BOOT_PROTOCOL */
@@ -728,10 +737,14 @@ efi_status_t efi_set_watchdog(unsigned long timeout);
void efi_timer_check(void);
/* Check if a buffer contains a PE-COFF image */
efi_status_t efi_check_pe(void *buffer, size_t size, void **nt_header);
+/* Verify a PE image's signature against secure boot databases */
+bool efi_image_authenticate(void *efi, size_t efi_size);
/* PE loader implementation */
efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
void *efi, size_t efi_size,
- struct efi_loaded_image *loaded_image_info);
+ struct efi_loaded_image *loaded_image_info,
+ struct efi_device_path *file_path,
+ bool boot_policy);
/* Called once to store the pristine gd pointer */
void efi_save_gd(void);
/* Call this to relocate the runtime section to an address space */
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 4cb13ae7c8a..b253af121a4 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -71,6 +71,17 @@ config EFI_SECURE_BOOT
it is signed with a trusted key. To do that, you need to install,
at least, PK, KEK and db.
+config EFI_SECURITY_ARCH_PROTOCOL
+ bool "Install EFI Security Architecture Protocols"
+ depends on EFI_SECURE_BOOT
+ default y
+ help
+ Install EFI_SECURITY_ARCH_PROTOCOL and
+ EFI_SECURITY2_ARCH_PROTOCOL. These allow EFI applications
+ (such as systemd-stub in Unified Kernel Images) to temporarily
+ override secure boot authentication for embedded payloads that
+ were already verified as part of a signed PE binary.
+
config EFI_SIGNATURE_SUPPORT
bool
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index d73ad43951b..2cfa33bb114 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_EFI_HTTP_PROTOCOL) += efi_http.o
obj-$(CONFIG_ACPI) += efi_acpi.o
obj-$(CONFIG_SMBIOS) += efi_smbios.o
obj-$(CONFIG_EFI_RNG_PROTOCOL) += efi_rng.o
+obj-$(CONFIG_EFI_SECURITY_ARCH_PROTOCOL) += efi_security.o
obj-$(CONFIG_EFI_TCG2_PROTOCOL) += efi_tcg2.o
obj-$(CONFIG_EFI_RISCV_BOOT_PROTOCOL) += efi_riscv.o
obj-$(CONFIG_EFI_LOAD_FILE2_INITRD) += efi_load_initrd.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index de57823bd44..934bdd89a69 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2120,7 +2120,8 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy,
efi_dp_split_file_path(file_path, &dp, &fp);
ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
if (ret == EFI_SUCCESS)
- ret = efi_load_pe(*image_obj, dest_buffer, source_size, info);
+ ret = efi_load_pe(*image_obj, dest_buffer, source_size, info,
+ file_path, boot_policy);
if (!source_buffer)
/* Release buffer to which file was loaded */
efi_free_pages((uintptr_t)dest_buffer,
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index f9a2d2df405..f128aabf142 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -641,7 +641,7 @@ static bool efi_image_verify_digest(struct efi_image_regions *regs,
*
* Return: true if authenticated, false if not
*/
-static bool efi_image_authenticate(void *efi, size_t efi_size)
+bool efi_image_authenticate(void *efi, size_t efi_size)
{
struct efi_image_regions *regs = NULL;
WIN_CERTIFICATE *wincerts = NULL, *wincert;
@@ -818,7 +818,7 @@ out:
return ret;
}
#else
-static bool efi_image_authenticate(void *efi, size_t efi_size)
+bool efi_image_authenticate(void *efi, size_t efi_size)
{
return true;
}
@@ -890,11 +890,15 @@ static u32 section_size(IMAGE_SECTION_HEADER *sec)
* @efi: pointer to the EFI binary
* @efi_size: size of @efi binary
* @loaded_image_info: loaded image protocol
+ * @file_path: device path of the image (for security protocol)
+ * @boot_policy: true if loading as a boot option
* Return: status code
*/
efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
void *efi, size_t efi_size,
- struct efi_loaded_image *loaded_image_info)
+ struct efi_loaded_image *loaded_image_info,
+ struct efi_device_path *file_path,
+ bool boot_policy)
{
IMAGE_NT_HEADERS32 *nt;
IMAGE_DOS_HEADER *dos;
@@ -939,11 +943,24 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
}
/* Authenticate an image */
- if (efi_image_authenticate(efi, efi_size)) {
- handle->auth_status = EFI_IMAGE_AUTH_PASSED;
+ if (IS_ENABLED(CONFIG_EFI_SECURITY_ARCH_PROTOCOL)) {
+ efi_status_t auth_ret;
+
+ auth_ret = efi_security_check_image(file_path, efi, efi_size,
+ boot_policy);
+ if (auth_ret == EFI_SUCCESS) {
+ handle->auth_status = EFI_IMAGE_AUTH_PASSED;
+ } else {
+ handle->auth_status = EFI_IMAGE_AUTH_FAILED;
+ log_err("Image not authenticated\n");
+ }
} else {
- handle->auth_status = EFI_IMAGE_AUTH_FAILED;
- log_err("Image not authenticated\n");
+ if (efi_image_authenticate(efi, efi_size)) {
+ handle->auth_status = EFI_IMAGE_AUTH_PASSED;
+ } else {
+ handle->auth_status = EFI_IMAGE_AUTH_FAILED;
+ log_err("Image not authenticated\n");
+ }
}
/* Calculate upper virtual address boundary */
diff --git a/lib/efi_loader/efi_security.c b/lib/efi_loader/efi_security.c
new file mode 100644
index 00000000000..66f2e79ad31
--- /dev/null
+++ b/lib/efi_loader/efi_security.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI Security Architecture Protocol implementation
+ *
+ * Implements EFI_SECURITY_ARCH_PROTOCOL and EFI_SECURITY2_ARCH_PROTOCOL
+ * as defined in the UEFI Platform Initialization (PI) specification.
+ *
+ * These protocols allow EFI applications (such as systemd-stub in Unified
+ * Kernel Images) to temporarily override secure boot authentication for
+ * embedded payloads that were already verified as part of a signed PE binary.
+ */
+
+#define LOG_CATEGORY LOGC_EFI
+
+#include <efi_loader.h>
+#include <log.h>
+
+const efi_guid_t efi_guid_security_arch_protocol =
+ EFI_SECURITY_ARCH_PROTOCOL_GUID;
+const efi_guid_t efi_guid_security2_arch_protocol =
+ EFI_SECURITY2_ARCH_PROTOCOL_GUID;
+
+static efi_status_t EFIAPI
+default_file_auth_state(const struct efi_security_arch_protocol *this,
+ u32 authentication_status,
+ const struct efi_device_path *file)
+{
+ return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI
+default_file_authentication(const struct efi_security2_arch_protocol *this,
+ const struct efi_device_path *device_path,
+ void *file_buffer, efi_uintn_t file_size,
+ bool boot_policy)
+{
+ if (efi_image_authenticate(file_buffer, file_size))
+ return EFI_SUCCESS;
+
+ return EFI_SECURITY_VIOLATION;
+}
+
+static struct efi_security_arch_protocol efi_security_arch = {
+ .file_authentication_state = default_file_auth_state,
+};
+
+static struct efi_security2_arch_protocol efi_security2_arch = {
+ .file_authentication = default_file_authentication,
+};
+
+/**
+ * efi_security_check_image() - authenticate image via Security2 protocol
+ *
+ * Calls the currently installed FileAuthentication callback on the
+ * EFI_SECURITY2_ARCH_PROTOCOL instance. This may be the default handler
+ * (which delegates to efi_image_authenticate()) or a custom override
+ * installed by an EFI application such as systemd-stub.
+ *
+ * @file_path: device path of the image being loaded
+ * @file_buffer: pointer to the image data
+ * @file_size: size of the image data
+ * @boot_policy: true if image is being loaded as a boot option
+ * Return: EFI_SUCCESS if authenticated, error code otherwise
+ */
+efi_status_t efi_security_check_image(const struct efi_device_path *file_path,
+ void *file_buffer, efi_uintn_t file_size,
+ bool boot_policy)
+{
+ return efi_security2_arch.file_authentication(&efi_security2_arch,
+ file_path, file_buffer,
+ file_size, boot_policy);
+}
+
+/**
+ * efi_security_arch_register() - install Security Architecture Protocols
+ *
+ * Installs both EFI_SECURITY_ARCH_PROTOCOL and EFI_SECURITY2_ARCH_PROTOCOL
+ * on the root handle during EFI subsystem initialization.
+ *
+ * Return: status code
+ */
+efi_status_t efi_security_arch_register(void)
+{
+ efi_status_t ret;
+
+ ret = efi_add_protocol(efi_root, &efi_guid_security_arch_protocol,
+ (void *)&efi_security_arch);
+ if (ret != EFI_SUCCESS) {
+ log_err("Cannot install EFI_SECURITY_ARCH_PROTOCOL\n");
+ return ret;
+ }
+
+ ret = efi_add_protocol(efi_root, &efi_guid_security2_arch_protocol,
+ (void *)&efi_security2_arch);
+ if (ret != EFI_SUCCESS)
+ log_err("Cannot install EFI_SECURITY2_ARCH_PROTOCOL\n");
+
+ return ret;
+}
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index f302bb62ab9..7c8ce129e22 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -338,6 +338,13 @@ efi_status_t efi_init_obj_list(void)
goto out;
}
+ /* Security Architecture Protocols */
+ if (IS_ENABLED(CONFIG_EFI_SECURITY_ARCH_PROTOCOL)) {
+ ret = efi_security_arch_register();
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
+
/* Indicate supported runtime services */
ret = efi_init_runtime_supported();
if (ret != EFI_SUCCESS)
--
2.54.0
More information about the U-Boot
mailing list