]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
stub: restore compatibility for shim (< 16.0) -> UKI case
authorLuca Boccassi <luca.boccassi@gmail.com>
Mon, 14 Jul 2025 23:52:01 +0000 (00:52 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 23 Jul 2025 07:54:09 +0000 (09:54 +0200)
It is possible to boot directly a UKI from shim, and Fedora Cloud Base UKI
does exactly this.
This used to work fine until https://github.com/systemd/systemd/pull/37372
which broke compatibility when shim < 16.0 (no loader protocol override) is
used. Shim 15.8 is still in use in several distributions, and will be for
a long time.

Restore a part of the previous implementation, and if running with secure
boot enabled, and with shim but < 16.0, apply a security override.

Follow-up for cab9c7b5a42effa8a45611fc6b8556138c869b5f

Fixes https://github.com/systemd/systemd/issues/38104

src/boot/linux.c

index 1e8fe15bd1b71598e9a61ce8405dc283cf770c72..655d151481bae9f5ff793d9a7153cc845097ddb0 100644 (file)
 #define STUB_PAYLOAD_GUID \
         { 0x55c5d1f8, 0x04cd, 0x46b5, { 0x8a, 0x20, 0xe5, 0x6c, 0xbb, 0x30, 0x52, 0xd0 } }
 
+typedef struct {
+        const void *addr;
+        size_t len;
+        const EFI_DEVICE_PATH *device_path;
+} ValidationContext;
+
+static bool validate_payload(
+                const void *ctx, const EFI_DEVICE_PATH *device_path, const void *file_buffer, size_t file_size) {
+
+        const ValidationContext *payload = ASSERT_PTR(ctx);
+
+        if (device_path != payload->device_path)
+                return false;
+
+        /* Security arch (1) protocol does not provide a file buffer. Instead we are supposed to fetch the payload
+         * ourselves, which is not needed as we already have everything in memory and the device paths match. */
+        if (file_buffer && (file_buffer != payload->addr || file_size != payload->len))
+                return false;
+
+        return true;
+}
+
 static EFI_STATUS load_via_boot_services(
                 EFI_HANDLE parent,
                 EFI_LOADED_IMAGE_PROTOCOL* parent_loaded_image,
@@ -43,6 +65,19 @@ static EFI_STATUS load_via_boot_services(
 
         _cleanup_free_ EFI_DEVICE_PATH* file_path = device_path_replace_node(parent_loaded_image->FilePath, NULL, &device_node.Header);
 
+        /* When running with shim < v16 and booting a UKI directly from it, without a second stage loader,
+         * the shim verify protocol needs to be called or it will raise a security violation when starting
+         * the image (e.g.: Fedora Cloud Base UKI). TODO: drop once support for shim < v16 is not needed. */
+        if (!shim_loader_available())
+                install_security_override(
+                                validate_payload,
+                                &(ValidationContext) {
+                                        .addr = kernel->iov_base,
+                                        .len = kernel->iov_len,
+                                        .device_path = file_path,
+                                });
+
+
         err = BS->LoadImage(/* BootPolicy= */false,
                             parent,
                             file_path,
@@ -50,6 +85,9 @@ static EFI_STATUS load_via_boot_services(
                             kernel->iov_len,
                             &kernel_image);
 
+        if (!shim_loader_available())
+                uninstall_security_override();
+
         if (err != EFI_SUCCESS)
                 return log_error_status(EFI_LOAD_ERROR, "Error loading inner kernel with shim: %m");
 
@@ -131,7 +169,7 @@ EFI_STATUS linux_exec(
          *
          * See https://github.com/rhboot/shim/blob/main/README.md#shim-loader-protocol
          */
-        if (secure_boot_enabled() && shim_loader_available())
+        if (secure_boot_enabled() && (shim_loader_available() || shim_loaded()))
                 return load_via_boot_services(
                                 parent,
                                 parent_loaded_image,