From 3ba0034d9ddf72bcc969d6b4a0e3ea3271339875 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Sat, 22 Apr 2023 19:53:28 +0100 Subject: [PATCH] Optionally allow to keep shim protocol installed If the ShimRetainProtocol variable is set, avoid uninstalling our protocol. For example, this allows sd-stub in a UKI to use the shim protocol to validate PE binaries, even if it is executed by a second stage, before the kernel is loaded. Ensure that the variable is volatile and for BootServices access. Also delete it on startup, so that we can be sure it was really set by a second stage. Example use case in sd-boot/sd-stub: https://github.com/systemd/systemd/pull/27358 Signed-off-by: Luca Boccassi --- MokVars.txt | 5 +++++ replacements.c | 21 ++++++++++++++++++++- shim.c | 6 ++++++ shim.h | 2 ++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/MokVars.txt b/MokVars.txt index cdfec2c8e..baf8db9a5 100644 --- a/MokVars.txt +++ b/MokVars.txt @@ -53,6 +53,11 @@ The hash will be regenerated by MokManager after the user is requested to enter their password to confirm enrolment of the keys. If the hash matches MokAuth, the user will be prompted to enrol the keys. BS,RT,NV +ShimRetainProtocol: UINT8, read by Shim before uninstalling protocol. +If set to non-zero, Shim will keep the protocol in place. It can be +used by second stages to ensure the protocol is still available for +later stages, and can thus be used to verify additional PE files. BS,RT. + State variables: MokList: A list of authorized keys and hashes. An EFI_SIGNATURE_LIST diff --git a/replacements.c b/replacements.c index bf781a8b5..6066f9d65 100644 --- a/replacements.c +++ b/replacements.c @@ -78,8 +78,27 @@ replacement_start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 * unhook_system_services(); if (image_handle == last_loaded_image) { + UINT8 retain_protocol = 0; + UINTN retain_protocol_size = sizeof(retain_protocol); + UINT32 retain_protocol_attrs = 0; + loader_is_participating = 1; - uninstall_shim_protocols(); + + /* If a boot component asks us, keep our protocol around - it will be used to + * validate further PE payloads (e.g.: by the UKI stub, before the kernel is booted). + * But also check that the variable was set by a boot component, to ensure that + * nobody at runtime can attempt to change shim's behaviour. */ + efi_status = RT->GetVariable(SHIM_RETAIN_PROTOCOL_VAR_NAME, + &SHIM_LOCK_GUID, + &retain_protocol_attrs, + &retain_protocol_size, + &retain_protocol); + if (EFI_ERROR(efi_status) || + (retain_protocol_attrs & EFI_VARIABLE_NON_VOLATILE) || + !(retain_protocol_attrs & EFI_VARIABLE_BOOTSERVICE_ACCESS) || + retain_protocol_size != sizeof(retain_protocol) || + retain_protocol == 0) + uninstall_shim_protocols(); } efi_status = BS->StartImage(image_handle, exit_data_size, exit_data); if (EFI_ERROR(efi_status)) { diff --git a/shim.c b/shim.c index 27a8c112f..e54f63458 100644 --- a/shim.c +++ b/shim.c @@ -1791,6 +1791,12 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab) #endif } + /* + * This variable is supposed to be set by second stages, so ensure it is + * not set when we are starting up. + */ + (void) del_variable(SHIM_RETAIN_PROTOCOL_VAR_NAME, SHIM_LOCK_GUID); + efi_status = shim_init(); if (EFI_ERROR(efi_status)) { msg = SHIM_INIT; diff --git a/shim.h b/shim.h index 14824c67a..3e221b50f 100644 --- a/shim.h +++ b/shim.h @@ -305,6 +305,8 @@ verify_buffer (char *data, int datasize, #define DEBUG_VAR_NAME L"SHIM_DEBUG" #endif +#define SHIM_RETAIN_PROTOCOL_VAR_NAME L"ShimRetainProtocol" + char *translate_slashes(char *out, const char *str); #endif /* SHIM_H_ */