Merge pull request #25222 from medhefgo/stub-cmdline
stub: Fix cmdline handling
This commit is contained in:
+22
-24
@@ -1204,7 +1204,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
|
||||
continue;
|
||||
}
|
||||
free(config->entry_default_config);
|
||||
config->entry_default_config = xstra_to_str(value);
|
||||
config->entry_default_config = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1418,32 +1418,32 @@ static void config_entry_add_type1(
|
||||
while ((line = line_get_key_value(content, " \t", &pos, &key, &value))) {
|
||||
if (streq8(key, "title")) {
|
||||
free(entry->title);
|
||||
entry->title = xstra_to_str(value);
|
||||
entry->title = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "sort-key")) {
|
||||
free(entry->sort_key);
|
||||
entry->sort_key = xstra_to_str(value);
|
||||
entry->sort_key = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "version")) {
|
||||
free(entry->version);
|
||||
entry->version = xstra_to_str(value);
|
||||
entry->version = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "machine-id")) {
|
||||
free(entry->machine_id);
|
||||
entry->machine_id = xstra_to_str(value);
|
||||
entry->machine_id = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "linux")) {
|
||||
free(entry->loader);
|
||||
entry->type = LOADER_LINUX;
|
||||
entry->loader = xstra_to_path(value);
|
||||
entry->loader = xstr8_to_path(value);
|
||||
entry->key = 'l';
|
||||
continue;
|
||||
}
|
||||
@@ -1451,7 +1451,7 @@ static void config_entry_add_type1(
|
||||
if (streq8(key, "efi")) {
|
||||
entry->type = LOADER_EFI;
|
||||
free(entry->loader);
|
||||
entry->loader = xstra_to_path(value);
|
||||
entry->loader = xstr8_to_path(value);
|
||||
|
||||
/* do not add an entry for ourselves */
|
||||
if (strcaseeq16(entry->loader, loaded_image_path)) {
|
||||
@@ -1472,7 +1472,7 @@ static void config_entry_add_type1(
|
||||
|
||||
if (streq8(key, "devicetree")) {
|
||||
free(entry->devicetree);
|
||||
entry->devicetree = xstra_to_path(value);
|
||||
entry->devicetree = xstr8_to_path(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1481,7 +1481,7 @@ static void config_entry_add_type1(
|
||||
entry->initrd,
|
||||
n_initrd == 0 ? 0 : (n_initrd + 1) * sizeof(uint16_t *),
|
||||
(n_initrd + 2) * sizeof(uint16_t *));
|
||||
entry->initrd[n_initrd++] = xstra_to_path(value);
|
||||
entry->initrd[n_initrd++] = xstr8_to_path(value);
|
||||
entry->initrd[n_initrd] = NULL;
|
||||
continue;
|
||||
}
|
||||
@@ -1489,7 +1489,7 @@ static void config_entry_add_type1(
|
||||
if (streq8(key, "options")) {
|
||||
_cleanup_free_ char16_t *new = NULL;
|
||||
|
||||
new = xstra_to_str(value);
|
||||
new = xstr8_to_16(value);
|
||||
if (entry->options) {
|
||||
char16_t *s = xpool_print(L"%s %s", entry->options, new);
|
||||
free(entry->options);
|
||||
@@ -2134,49 +2134,49 @@ static void config_entry_add_unified(
|
||||
while ((line = line_get_key_value(content, "=", &pos, &key, &value))) {
|
||||
if (streq8(key, "PRETTY_NAME")) {
|
||||
free(os_pretty_name);
|
||||
os_pretty_name = xstra_to_str(value);
|
||||
os_pretty_name = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "IMAGE_ID")) {
|
||||
free(os_image_id);
|
||||
os_image_id = xstra_to_str(value);
|
||||
os_image_id = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "NAME")) {
|
||||
free(os_name);
|
||||
os_name = xstra_to_str(value);
|
||||
os_name = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "ID")) {
|
||||
free(os_id);
|
||||
os_id = xstra_to_str(value);
|
||||
os_id = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "IMAGE_VERSION")) {
|
||||
free(os_image_version);
|
||||
os_image_version = xstra_to_str(value);
|
||||
os_image_version = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "VERSION")) {
|
||||
free(os_version);
|
||||
os_version = xstra_to_str(value);
|
||||
os_version = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "VERSION_ID")) {
|
||||
free(os_version_id);
|
||||
os_version_id = xstra_to_str(value);
|
||||
os_version_id = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (streq8(key, "BUILD_ID")) {
|
||||
free(os_build_id);
|
||||
os_build_id = xstra_to_str(value);
|
||||
os_build_id = xstr8_to_16(value);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -2219,13 +2219,11 @@ static void config_entry_add_unified(
|
||||
content = mfree(content);
|
||||
|
||||
/* read the embedded cmdline file */
|
||||
err = file_read(linux_dir, f->FileName, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, NULL);
|
||||
size_t cmdline_len;
|
||||
err = file_read(linux_dir, f->FileName, offs[SECTION_CMDLINE], szs[SECTION_CMDLINE], &content, &cmdline_len);
|
||||
if (err == EFI_SUCCESS) {
|
||||
/* chomp the newline */
|
||||
if (content[szs[SECTION_CMDLINE] - 1] == '\n')
|
||||
content[szs[SECTION_CMDLINE] - 1] = '\0';
|
||||
|
||||
entry->options = xstra_to_str(content);
|
||||
entry->options = xstrn8_to_16(content, cmdline_len);
|
||||
mangle_stub_cmdline(entry->options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-18
@@ -359,24 +359,7 @@ static char16_t *get_dropin_dir(const EFI_DEVICE_PATH *file_path) {
|
||||
if (device_path_to_str(file_path, &file_path_str) != EFI_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
for (char16_t *i = file_path_str, *fixed = i;; i++) {
|
||||
if (*i == '\0') {
|
||||
*fixed = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
/* Fix device path node separator. */
|
||||
if (*i == '/')
|
||||
*i = '\\';
|
||||
|
||||
/* Double '\' is not allowed in EFI file paths. */
|
||||
if (fixed != file_path_str && fixed[-1] == '\\' && *i == '\\')
|
||||
continue;
|
||||
|
||||
*fixed = *i;
|
||||
fixed++;
|
||||
}
|
||||
|
||||
convert_efi_path(file_path_str);
|
||||
return xpool_print(u"%s.extra.d", file_path_str);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
# include "util.h"
|
||||
#else
|
||||
# include <stdlib.h>
|
||||
# include "macro.h"
|
||||
# include "alloc-util.h"
|
||||
# define xnew(t, n) ASSERT_SE_PTR(new(t, n))
|
||||
# define xmalloc(n) ASSERT_SE_PTR(malloc(n))
|
||||
#endif
|
||||
|
||||
@@ -138,6 +139,81 @@ DEFINE_STRCHR(char16_t, strchr16);
|
||||
DEFINE_STRNDUP(char, xstrndup8, strnlen8);
|
||||
DEFINE_STRNDUP(char16_t, xstrndup16, strnlen16);
|
||||
|
||||
static unsigned utf8_to_unichar(const char *utf8, size_t n, char32_t *c) {
|
||||
char32_t unichar;
|
||||
unsigned len;
|
||||
|
||||
assert(utf8);
|
||||
assert(c);
|
||||
|
||||
if (!(utf8[0] & 0x80)) {
|
||||
*c = utf8[0];
|
||||
return 1;
|
||||
} else if ((utf8[0] & 0xe0) == 0xc0) {
|
||||
len = 2;
|
||||
unichar = utf8[0] & 0x1f;
|
||||
} else if ((utf8[0] & 0xf0) == 0xe0) {
|
||||
len = 3;
|
||||
unichar = utf8[0] & 0x0f;
|
||||
} else if ((utf8[0] & 0xf8) == 0xf0) {
|
||||
len = 4;
|
||||
unichar = utf8[0] & 0x07;
|
||||
} else if ((utf8[0] & 0xfc) == 0xf8) {
|
||||
len = 5;
|
||||
unichar = utf8[0] & 0x03;
|
||||
} else if ((utf8[0] & 0xfe) == 0xfc) {
|
||||
len = 6;
|
||||
unichar = utf8[0] & 0x01;
|
||||
} else {
|
||||
*c = UINT32_MAX;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (len > n) {
|
||||
*c = UINT32_MAX;
|
||||
return len;
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i < len; i++) {
|
||||
if ((utf8[i] & 0xc0) != 0x80) {
|
||||
*c = UINT32_MAX;
|
||||
return len;
|
||||
}
|
||||
unichar <<= 6;
|
||||
unichar |= utf8[i] & 0x3f;
|
||||
}
|
||||
|
||||
*c = unichar;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Convert UTF-8 to UCS-2, skipping any invalid or short byte sequences. */
|
||||
char16_t *xstrn8_to_16(const char *str8, size_t n) {
|
||||
if (!str8 || n == 0)
|
||||
return NULL;
|
||||
|
||||
size_t i = 0;
|
||||
char16_t *str16 = xnew(char16_t, n + 1);
|
||||
|
||||
while (n > 0 && *str8 != '\0') {
|
||||
char32_t unichar;
|
||||
|
||||
size_t utf8len = utf8_to_unichar(str8, n, &unichar);
|
||||
str8 += utf8len;
|
||||
n = LESS_BY(n, utf8len);
|
||||
|
||||
switch (unichar) {
|
||||
case 0 ... 0xd7ffU:
|
||||
case 0xe000U ... 0xffffU:
|
||||
str16[i++] = unichar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
str16[i] = '\0';
|
||||
return str16;
|
||||
}
|
||||
|
||||
static bool efi_fnmatch_prefix(const char16_t *p, const char16_t *h, const char16_t **ret_p, const char16_t **ret_h) {
|
||||
assert(p);
|
||||
assert(h);
|
||||
|
||||
@@ -99,6 +99,11 @@ static inline char16_t *xstrdup16(const char16_t *s) {
|
||||
return xstrndup16(s, SIZE_MAX);
|
||||
}
|
||||
|
||||
char16_t *xstrn8_to_16(const char *str8, size_t n);
|
||||
static inline char16_t *xstr8_to_16(const char *str8) {
|
||||
return xstrn8_to_16(str8, strlen8(str8));
|
||||
}
|
||||
|
||||
bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack);
|
||||
|
||||
bool parse_number8(const char *s, uint64_t *ret_u, const char **ret_tail);
|
||||
|
||||
@@ -93,15 +93,16 @@ static EFI_STATUS load_image(EFI_HANDLE parent, const void *source, size_t len,
|
||||
|
||||
EFI_STATUS linux_exec(
|
||||
EFI_HANDLE parent,
|
||||
const char *cmdline, UINTN cmdline_len,
|
||||
const void *linux_buffer, UINTN linux_length,
|
||||
const void *initrd_buffer, UINTN initrd_length) {
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length) {
|
||||
|
||||
uint32_t compat_address;
|
||||
EFI_STATUS err;
|
||||
|
||||
assert(parent);
|
||||
assert(cmdline || cmdline_len == 0);
|
||||
assert(linux_buffer && linux_length > 0);
|
||||
assert(initrd_buffer || initrd_length == 0);
|
||||
|
||||
@@ -113,7 +114,6 @@ EFI_STATUS linux_exec(
|
||||
return linux_exec_efi_handover(
|
||||
parent,
|
||||
cmdline,
|
||||
cmdline_len,
|
||||
linux_buffer,
|
||||
linux_length,
|
||||
initrd_buffer,
|
||||
@@ -133,7 +133,7 @@ EFI_STATUS linux_exec(
|
||||
return log_error_status_stall(err, u"Error getting kernel loaded image protocol: %r", err);
|
||||
|
||||
if (cmdline) {
|
||||
loaded_image->LoadOptions = xstra_to_str(cmdline);
|
||||
loaded_image->LoadOptions = (void *) cmdline;
|
||||
loaded_image->LoadOptionsSize = strsize16(loaded_image->LoadOptions);
|
||||
}
|
||||
|
||||
|
||||
+11
-6
@@ -2,14 +2,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <efi.h>
|
||||
#include <uchar.h>
|
||||
|
||||
EFI_STATUS linux_exec(
|
||||
EFI_HANDLE parent,
|
||||
const char *cmdline, UINTN cmdline_len,
|
||||
const void *linux_buffer, UINTN linux_length,
|
||||
const void *initrd_buffer, UINTN initrd_length);
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length);
|
||||
EFI_STATUS linux_exec_efi_handover(
|
||||
EFI_HANDLE parent,
|
||||
const char *cmdline, UINTN cmdline_len,
|
||||
const void *linux_buffer, UINTN linux_length,
|
||||
const void *initrd_buffer, UINTN initrd_length);
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length);
|
||||
|
||||
@@ -126,12 +126,13 @@ static void linux_efi_handover(EFI_HANDLE parent, uintptr_t kernel, BootParams *
|
||||
|
||||
EFI_STATUS linux_exec_efi_handover(
|
||||
EFI_HANDLE parent,
|
||||
const char *cmdline, UINTN cmdline_len,
|
||||
const void *linux_buffer, UINTN linux_length,
|
||||
const void *initrd_buffer, UINTN initrd_length) {
|
||||
const char16_t *cmdline,
|
||||
const void *linux_buffer,
|
||||
size_t linux_length,
|
||||
const void *initrd_buffer,
|
||||
size_t initrd_length) {
|
||||
|
||||
assert(parent);
|
||||
assert(cmdline || cmdline_len == 0);
|
||||
assert(linux_buffer);
|
||||
assert(initrd_buffer || initrd_length == 0);
|
||||
|
||||
@@ -185,14 +186,20 @@ EFI_STATUS linux_exec_efi_handover(
|
||||
|
||||
_cleanup_pages_ Pages cmdline_pages = {};
|
||||
if (cmdline) {
|
||||
size_t len = MIN(strlen16(cmdline), image_params->hdr.cmdline_size);
|
||||
|
||||
cmdline_pages = xmalloc_pages(
|
||||
can_4g ? AllocateAnyPages : AllocateMaxAddress,
|
||||
EfiLoaderData,
|
||||
EFI_SIZE_TO_PAGES(cmdline_len + 1),
|
||||
EFI_SIZE_TO_PAGES(len + 1),
|
||||
CMDLINE_PTR_MAX);
|
||||
|
||||
memcpy(PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr), cmdline, cmdline_len);
|
||||
((char *) PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr))[cmdline_len] = 0;
|
||||
/* Convert cmdline to ASCII. */
|
||||
char *cmdline8 = PHYSICAL_ADDRESS_TO_POINTER(cmdline_pages.addr);
|
||||
for (size_t i = 0; i < len; i++)
|
||||
cmdline8[i] = cmdline[i] <= 0x7E ? cmdline[i] : ' ';
|
||||
cmdline8[len] = '\0';
|
||||
|
||||
boot_params->hdr.cmd_line_ptr = (uint32_t) cmdline_pages.addr;
|
||||
boot_params->ext_cmd_line_ptr = cmdline_pages.addr >> 32;
|
||||
assert(can_4g || cmdline_pages.addr <= CMDLINE_PTR_MAX);
|
||||
|
||||
@@ -187,7 +187,7 @@ EFI_STATUS tpm_log_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, U
|
||||
_cleanup_free_ char16_t *c = NULL;
|
||||
|
||||
if (description)
|
||||
c = xstra_to_str(description);
|
||||
c = xstr8_to_16(description);
|
||||
|
||||
return tpm_log_event(pcrindex, buffer, buffer_size, c, ret_measured);
|
||||
}
|
||||
|
||||
@@ -385,3 +385,16 @@ typedef struct _EFI_CONSOLE_CONTROL_PROTOCOL {
|
||||
{ 0xd719b2cb, 0x3d3a, 0x4596, {0xa3, 0xbc, 0xda, 0xd0, 0xe, 0x67, 0x65, 0x6f }}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef EFI_SHELL_PARAMETERS_PROTOCOL_GUID
|
||||
# define EFI_SHELL_PARAMETERS_PROTOCOL_GUID \
|
||||
{ 0x752f3136, 0x4e16, 0x4fdc, { 0xa2, 0x2a, 0xe5, 0xf4, 0x68, 0x12, 0xf4, 0xca } }
|
||||
|
||||
typedef struct {
|
||||
CHAR16 **Argv;
|
||||
UINTN Argc;
|
||||
void *StdIn;
|
||||
void *StdOut;
|
||||
void *StdErr;
|
||||
} EFI_SHELL_PARAMETERS_PROTOCOL;
|
||||
#endif
|
||||
|
||||
+59
-26
@@ -133,16 +133,62 @@ static void export_variables(EFI_LOADED_IMAGE_PROTOCOL *loaded_image) {
|
||||
(void) efivar_set_uint64_le(LOADER_GUID, L"StubFeatures", stub_features, 0);
|
||||
}
|
||||
|
||||
static bool use_load_options(
|
||||
EFI_HANDLE stub_image,
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image,
|
||||
bool have_cmdline,
|
||||
char16_t **ret) {
|
||||
|
||||
assert(stub_image);
|
||||
assert(loaded_image);
|
||||
assert(ret);
|
||||
|
||||
/* We only allow custom command lines if we aren't in secure boot or if no cmdline was baked into
|
||||
* the stub image. */
|
||||
if (secure_boot_enabled() && have_cmdline)
|
||||
return false;
|
||||
|
||||
/* We also do a superficial check whether first character of passed command line
|
||||
* is printable character (for compat with some Dell systems which fill in garbage?). */
|
||||
if (loaded_image->LoadOptionsSize < sizeof(char16_t) || ((char16_t *) loaded_image->LoadOptions)[0] <= 0x1F)
|
||||
return false;
|
||||
|
||||
/* The UEFI shell registers EFI_SHELL_PARAMETERS_PROTOCOL onto images it runs. This lets us know that
|
||||
* LoadOptions starts with the stub binary path which we want to strip off. */
|
||||
EFI_SHELL_PARAMETERS_PROTOCOL *shell;
|
||||
if (BS->HandleProtocol(stub_image, &(EFI_GUID) EFI_SHELL_PARAMETERS_PROTOCOL_GUID, (void **) &shell)
|
||||
!= EFI_SUCCESS) {
|
||||
/* Not running from EFI shell, use entire LoadOptions. Note that LoadOptions is a void*, so
|
||||
* it could be anything! */
|
||||
*ret = xstrndup16(loaded_image->LoadOptions, loaded_image->LoadOptionsSize / sizeof(char16_t));
|
||||
mangle_stub_cmdline(*ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (shell->Argc < 2)
|
||||
/* No arguments were provided? Then we fall back to built-in cmdline. */
|
||||
return false;
|
||||
|
||||
/* Assemble the command line ourselves without our stub path. */
|
||||
*ret = xstrdup16(shell->Argv[1]);
|
||||
for (size_t i = 2; i < shell->Argc; i++) {
|
||||
_cleanup_free_ char16_t *old = *ret;
|
||||
*ret = xpool_print(u"%s %s", old, shell->Argv[i]);
|
||||
}
|
||||
|
||||
mangle_stub_cmdline(*ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
_cleanup_free_ void *credential_initrd = NULL, *global_credential_initrd = NULL, *sysext_initrd = NULL, *pcrsig_initrd = NULL, *pcrpkey_initrd = NULL;
|
||||
UINTN credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
|
||||
UINTN cmdline_len = 0, linux_size, initrd_size, dt_size;
|
||||
size_t credential_initrd_size = 0, global_credential_initrd_size = 0, sysext_initrd_size = 0, pcrsig_initrd_size = 0, pcrpkey_initrd_size = 0;
|
||||
size_t linux_size, initrd_size, dt_size;
|
||||
EFI_PHYSICAL_ADDRESS linux_base, initrd_base, dt_base;
|
||||
_cleanup_(devicetree_cleanup) struct devicetree_state dt_state = {};
|
||||
EFI_LOADED_IMAGE_PROTOCOL *loaded_image;
|
||||
UINTN addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
|
||||
char *cmdline = NULL;
|
||||
_cleanup_free_ char *cmdline_owned = NULL;
|
||||
size_t addrs[_UNIFIED_SECTION_MAX] = {}, szs[_UNIFIED_SECTION_MAX] = {};
|
||||
_cleanup_free_ char16_t *cmdline = NULL;
|
||||
int sections_measured = -1, parameters_measured = -1;
|
||||
bool sysext_measured = false, m;
|
||||
uint64_t loader_features = 0;
|
||||
@@ -221,32 +267,19 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
/* Show splash screen as early as possible */
|
||||
graphics_splash((const uint8_t*) loaded_image->ImageBase + addrs[UNIFIED_SECTION_SPLASH], szs[UNIFIED_SECTION_SPLASH]);
|
||||
|
||||
if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
|
||||
cmdline = (char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE];
|
||||
cmdline_len = szs[UNIFIED_SECTION_CMDLINE];
|
||||
}
|
||||
|
||||
/* if we are not in secure boot mode, or none was provided, accept a custom command line and replace
|
||||
* the built-in one. We also do a superficial check whether first character of passed command line
|
||||
* is printable character (for compat with some Dell systems which fill in garbage?). */
|
||||
if ((!secure_boot_enabled() || cmdline_len == 0) &&
|
||||
loaded_image->LoadOptionsSize > 0 &&
|
||||
((char16_t *) loaded_image->LoadOptions)[0] > 0x1F) {
|
||||
cmdline_len = (loaded_image->LoadOptionsSize / sizeof(char16_t)) * sizeof(char);
|
||||
cmdline = cmdline_owned = xnew(char, cmdline_len);
|
||||
|
||||
for (UINTN i = 0; i < cmdline_len; i++) {
|
||||
char16_t c = ((char16_t *) loaded_image->LoadOptions)[i];
|
||||
cmdline[i] = c > 0x1F && c < 0x7F ? c : ' '; /* convert non-printable and non_ASCII characters to spaces. */
|
||||
}
|
||||
|
||||
if (use_load_options(image, loaded_image, szs[UNIFIED_SECTION_CMDLINE] > 0, &cmdline)) {
|
||||
/* Let's measure the passed kernel command line into the TPM. Note that this possibly
|
||||
* duplicates what we already did in the boot menu, if that was already used. However, since
|
||||
* we want the boot menu to support an EFI binary, and want to this stub to be usable from
|
||||
* any boot menu, let's measure things anyway. */
|
||||
m = false;
|
||||
(void) tpm_log_load_options(loaded_image->LoadOptions, &m);
|
||||
(void) tpm_log_load_options(cmdline, &m);
|
||||
parameters_measured = m;
|
||||
} else if (szs[UNIFIED_SECTION_CMDLINE] > 0) {
|
||||
cmdline = xstrn8_to_16(
|
||||
(char *) loaded_image->ImageBase + addrs[UNIFIED_SECTION_CMDLINE],
|
||||
szs[UNIFIED_SECTION_CMDLINE]);
|
||||
mangle_stub_cmdline(cmdline);
|
||||
}
|
||||
|
||||
export_variables(loaded_image);
|
||||
@@ -387,7 +420,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
|
||||
log_error_stall(L"Error loading embedded devicetree: %r", err);
|
||||
}
|
||||
|
||||
err = linux_exec(image, cmdline, cmdline_len,
|
||||
err = linux_exec(image, cmdline,
|
||||
PHYSICAL_ADDRESS_TO_POINTER(linux_base), linux_size,
|
||||
PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
|
||||
graphics_mode(false);
|
||||
|
||||
@@ -324,6 +324,33 @@ TEST(xstrdup16) {
|
||||
free(s);
|
||||
}
|
||||
|
||||
TEST(xstrn8_to_16) {
|
||||
char16_t *s = NULL;
|
||||
|
||||
assert_se(xstrn8_to_16(NULL, 1) == NULL);
|
||||
assert_se(xstrn8_to_16("a", 0) == NULL);
|
||||
|
||||
assert_se(s = xstrn8_to_16("", 1));
|
||||
assert_se(streq16(s, u""));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrn8_to_16("1", 1));
|
||||
assert_se(streq16(s, u"1"));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstr8_to_16("abcxyzABCXYZ09 .,-_#*!\"§$%&/()=?`~"));
|
||||
assert_se(streq16(s, u"abcxyzABCXYZ09 .,-_#*!\"§$%&/()=?`~"));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstr8_to_16("ÿⱿ𝇉 😺"));
|
||||
assert_se(streq16(s, u"ÿⱿ "));
|
||||
free(s);
|
||||
|
||||
assert_se(s = xstrn8_to_16("¶¶", 3));
|
||||
assert_se(streq16(s, u"¶"));
|
||||
free(s);
|
||||
}
|
||||
|
||||
#define TEST_FNMATCH_ONE(pattern, haystack, expect) \
|
||||
({ \
|
||||
assert_se(fnmatch(pattern, haystack, 0) == (expect ? 0 : FNM_NOMATCH)); \
|
||||
|
||||
+22
-113
@@ -244,127 +244,36 @@ void efivar_set_time_usec(const EFI_GUID *vendor, const char16_t *name, uint64_t
|
||||
efivar_set(vendor, name, str, 0);
|
||||
}
|
||||
|
||||
static int utf8_to_16(const char *stra, char16_t *c) {
|
||||
char16_t unichar;
|
||||
UINTN len;
|
||||
void convert_efi_path(char16_t *path) {
|
||||
assert(path);
|
||||
|
||||
assert(stra);
|
||||
assert(c);
|
||||
for (size_t i = 0, fixed = 0;; i++) {
|
||||
/* Fix device path node separator. */
|
||||
path[fixed] = (path[i] == '/') ? '\\' : path[i];
|
||||
|
||||
if (!(stra[0] & 0x80))
|
||||
len = 1;
|
||||
else if ((stra[0] & 0xe0) == 0xc0)
|
||||
len = 2;
|
||||
else if ((stra[0] & 0xf0) == 0xe0)
|
||||
len = 3;
|
||||
else if ((stra[0] & 0xf8) == 0xf0)
|
||||
len = 4;
|
||||
else if ((stra[0] & 0xfc) == 0xf8)
|
||||
len = 5;
|
||||
else if ((stra[0] & 0xfe) == 0xfc)
|
||||
len = 6;
|
||||
else
|
||||
return -1;
|
||||
/* Double '\' is not allowed in EFI file paths. */
|
||||
if (fixed > 0 && path[fixed - 1] == '\\' && path[fixed] == '\\')
|
||||
continue;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
unichar = stra[0];
|
||||
break;
|
||||
case 2:
|
||||
unichar = stra[0] & 0x1f;
|
||||
break;
|
||||
case 3:
|
||||
unichar = stra[0] & 0x0f;
|
||||
break;
|
||||
case 4:
|
||||
unichar = stra[0] & 0x07;
|
||||
break;
|
||||
case 5:
|
||||
unichar = stra[0] & 0x03;
|
||||
break;
|
||||
case 6:
|
||||
unichar = stra[0] & 0x01;
|
||||
break;
|
||||
if (path[i] == '\0')
|
||||
break;
|
||||
|
||||
fixed++;
|
||||
}
|
||||
|
||||
for (UINTN i = 1; i < len; i++) {
|
||||
if ((stra[i] & 0xc0) != 0x80)
|
||||
return -1;
|
||||
unichar <<= 6;
|
||||
unichar |= stra[i] & 0x3f;
|
||||
}
|
||||
|
||||
*c = unichar;
|
||||
return len;
|
||||
}
|
||||
|
||||
char16_t *xstra_to_str(const char *stra) {
|
||||
UINTN strlen;
|
||||
UINTN len;
|
||||
UINTN i;
|
||||
char16_t *str;
|
||||
|
||||
assert(stra);
|
||||
|
||||
len = strlen8(stra);
|
||||
str = xnew(char16_t, len + 1);
|
||||
|
||||
strlen = 0;
|
||||
i = 0;
|
||||
while (i < len) {
|
||||
int utf8len;
|
||||
|
||||
utf8len = utf8_to_16(stra + i, str + strlen);
|
||||
if (utf8len <= 0) {
|
||||
/* invalid utf8 sequence, skip the garbage */
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlen++;
|
||||
i += utf8len;
|
||||
}
|
||||
str[strlen] = '\0';
|
||||
return str;
|
||||
char16_t *xstr8_to_path(const char *str8) {
|
||||
assert(str8);
|
||||
char16_t *path = xstr8_to_16(str8);
|
||||
convert_efi_path(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
char16_t *xstra_to_path(const char *stra) {
|
||||
char16_t *str;
|
||||
UINTN strlen;
|
||||
UINTN len;
|
||||
UINTN i;
|
||||
|
||||
assert(stra);
|
||||
|
||||
len = strlen8(stra);
|
||||
str = xnew(char16_t, len + 2);
|
||||
|
||||
str[0] = '\\';
|
||||
strlen = 1;
|
||||
i = 0;
|
||||
while (i < len) {
|
||||
int utf8len;
|
||||
|
||||
utf8len = utf8_to_16(stra + i, str + strlen);
|
||||
if (utf8len <= 0) {
|
||||
/* invalid utf8 sequence, skip the garbage */
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[strlen] == '/')
|
||||
str[strlen] = '\\';
|
||||
if (str[strlen] == '\\' && str[strlen-1] == '\\') {
|
||||
/* skip double slashes */
|
||||
i += utf8len;
|
||||
continue;
|
||||
}
|
||||
|
||||
strlen++;
|
||||
i += utf8len;
|
||||
}
|
||||
str[strlen] = '\0';
|
||||
return str;
|
||||
void mangle_stub_cmdline(char16_t *cmdline) {
|
||||
for (; *cmdline != '\0'; cmdline++)
|
||||
/* Convert ASCII control characters to spaces. */
|
||||
if (*cmdline <= 0x1F)
|
||||
*cmdline = ' ';
|
||||
}
|
||||
|
||||
EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **ret, UINTN *ret_size) {
|
||||
|
||||
+3
-2
@@ -137,8 +137,9 @@ EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const char16_t *name, ui
|
||||
EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const char16_t *name, uint64_t *ret);
|
||||
EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const char16_t *name, bool *ret);
|
||||
|
||||
char16_t *xstra_to_path(const char *stra);
|
||||
char16_t *xstra_to_str(const char *stra);
|
||||
void convert_efi_path(char16_t *path);
|
||||
char16_t *xstr8_to_path(const char *stra);
|
||||
void mangle_stub_cmdline(char16_t *cmdline);
|
||||
|
||||
EFI_STATUS file_read(EFI_FILE *dir, const char16_t *name, UINTN off, UINTN size, char **content, UINTN *content_size);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user