teknoraver / rpms / systemd

Forked from rpms/systemd 2 months ago
Clone

Blame SOURCES/0147-stub-Detect-empty-LoadOptions-when-run-from-EFI-shel.patch

2aacef
From c287f39f5df561968c4cb7712750e5ed23c02b29 Mon Sep 17 00:00:00 2001
2aacef
From: Jan Janssen <medhefgo@web.de>
2aacef
Date: Wed, 2 Nov 2022 10:25:32 +0100
2aacef
Subject: [PATCH] stub: Detect empty LoadOptions when run from EFI shell
2aacef
2aacef
The EFI shell will pass the entire command line to the application it
2aacef
starts, which includes the file path of the stub binary. This prevents
2aacef
us from using the built-in cmdline if the command line is otherwise
2aacef
empty.
2aacef
2aacef
Fortunately, the EFI shell registers a protocol on any images it starts
2aacef
this way. The protocol even lets us access the args individually, making
2aacef
it easy to strip the stub path off.
2aacef
2aacef
Fixes: #25201
2aacef
(cherry picked from commit b17f3b3d8077ab6827549a123ac636d655fe8d4d)
2aacef
2aacef
Related: #2138081
2aacef
---
2aacef
 src/boot/efi/missing_efi.h | 13 +++++++++
2aacef
 src/boot/efi/stub.c        | 59 +++++++++++++++++++++++++++++++-------
2aacef
 2 files changed, 61 insertions(+), 11 deletions(-)
2aacef
2aacef
diff --git a/src/boot/efi/missing_efi.h b/src/boot/efi/missing_efi.h
2aacef
index f9169248ec..250c84c248 100644
2aacef
--- a/src/boot/efi/missing_efi.h
2aacef
+++ b/src/boot/efi/missing_efi.h
2aacef
@@ -385,3 +385,16 @@ typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
2aacef
         { 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0,  0xe, 0x67, 0x65, 0x6f }}
2aacef
 
2aacef
 #endif
2aacef
+
2aacef
+#ifndef EFI_SHELL_PARAMETERS_PROTOCOL_GUID
2aacef
+#  define EFI_SHELL_PARAMETERS_PROTOCOL_GUID \
2aacef
+        { 0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } }
2aacef
+
2aacef
+typedef struct {
2aacef
+        CHAR16 **Argv;
2aacef
+        UINTN Argc;
2aacef
+        void *StdIn;
2aacef
+        void *StdOut;
2aacef
+        void *StdErr;
2aacef
+} EFI_SHELL_PARAMETERS_PROTOCOL;
2aacef
+#endif
2aacef
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
2aacef
index 841a0e41bd..7c42a16c70 100644
2aacef
--- a/src/boot/efi/stub.c
2aacef
+++ b/src/boot/efi/stub.c
2aacef
@@ -130,6 +130,53 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
2aacef
         (void) efivar_set_uint64_le(LOADER_GUID, L"StubFeatures", stub_features, 0);
2aacef
 }
2aacef
 
2aacef
+static bool use_load_options(
2aacef
+                EFI_HANDLE stub_image,
2aacef
+                EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
2aacef
+                bool have_cmdline,
2aacef
+                char16_t **ret) {
2aacef
+
2aacef
+        assert(stub_image);
2aacef
+        assert(loaded_image);
2aacef
+        assert(ret);
2aacef
+
2aacef
+        /* We only allow custom command lines if we aren't in secure boot or if no cmdline was baked into
2aacef
+         * the stub image. */
2aacef
+        if (secure_boot_enabled() && have_cmdline)
2aacef
+                return false;
2aacef
+
2aacef
+        /* We also do a superficial check whether first character of passed command line
2aacef
+         * is printable character (for compat with some Dell systems which fill in garbage?). */
2aacef
+        if (loaded_image->LoadOptionsSize < sizeof(char16_t) || ((char16_t *) loaded_image->LoadOptions)[0] <= 0x1F)
2aacef
+                return false;
2aacef
+
2aacef
+        /* The UEFI shell registers EFI_SHELL_PARAMETERS_PROTOCOL onto images it runs. This lets us know that
2aacef
+         * LoadOptions starts with the stub binary path which we want to strip off. */
2aacef
+        EFI_SHELL_PARAMETERS_PROTOCOL *shell;
2aacef
+        if (BS->HandleProtocol(stub_image, &(EFI_GUID) EFI_SHELL_PARAMETERS_PROTOCOL_GUID, (void **) &shell)
2aacef
+            != EFI_SUCCESS) {
2aacef
+                /* Not running from EFI shell, use entire LoadOptions. Note that LoadOptions is a void*, so
2aacef
+                 * it could be anything! */
2aacef
+                *ret = xstrndup16(loaded_image->LoadOptions, loaded_image->LoadOptionsSize / sizeof(char16_t));
2aacef
+                mangle_stub_cmdline(*ret);
2aacef
+                return true;
2aacef
+        }
2aacef
+
2aacef
+        if (shell->Argc < 2)
2aacef
+                /* No arguments were provided? Then we fall back to built-in cmdline. */
2aacef
+                return false;
2aacef
+
2aacef
+        /* Assemble the command line ourselves without our stub path. */
2aacef
+        *ret = xstrdup16(shell->Argv[1]);
2aacef
+        for (size_t i = 2; i < shell->Argc; i++) {
2aacef
+                _cleanup_free_ char16_t *old = *ret;
2aacef
+                *ret = xpool_print(u"%s %s", old, shell->Argv[i]);
2aacef
+        }
2aacef
+
2aacef
+        mangle_stub_cmdline(*ret);
2aacef
+        return true;
2aacef
+}
2aacef
+
2aacef
 EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
2aacef
         _cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
2aacef
         size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
2aacef
@@ -207,17 +254,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
2aacef
         /* Show splash screen as early as possible */
2aacef
         graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
2aacef
 
2aacef
-        /* if we are not in secure boot mode, or none was provided, accept a custom command line and replace
2aacef
-         * the built-in one. We also do a superficial check whether first character of passed command line
2aacef
-         * is printable character (for compat with some Dell systems which fill in garbage?). */
2aacef
-        if ((!secure_boot_enabled() || szs[UNIFIED_SECTION_CMDLINE] == 0) &&
2aacef
-            loaded_image->LoadOptionsSize > sizeof(char16_t) &&
2aacef
-            ((char16_t *) loaded_image->LoadOptions)[0] > 0x1F) {
2aacef
-                /* Note that LoadOptions is a void*, so it could be anything! */
2aacef
-                cmdline = xstrndup16(
2aacef
-                                loaded_image->LoadOptions, loaded_image->LoadOptionsSize / sizeof(char16_t));
2aacef
-                mangle_stub_cmdline(cmdline);
2aacef
-
2aacef
+        if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
2aacef
                 /* Let's measure the passed kernel command line into the TPM. Note that this possibly
2aacef
                  * duplicates what we already did in the boot menu, if that was already used. However, since
2aacef
                  * we want the boot menu to support an EFI binary, and want to this stub to be usable from