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