Merge pull request #20350 from medhefgo/boot

Grab bag of sd-boot improvements
This commit is contained in:
Lennart Poettering
2021-08-13 09:22:12 +02:00
committed by GitHub
21 changed files with 512 additions and 256 deletions
+2 -2
View File
@@ -41,8 +41,8 @@
a comment line. Empty and comment lines are ignored.</para>
<para>Boolean arguments may be written as
<literal>yes</literal>/<literal>y</literal>/<literal>true</literal>/<literal>1</literal> or
<literal>no</literal>/<literal>n</literal>/<literal>false</literal>/<literal>0</literal>.
<literal>yes</literal>/<literal>y</literal>/<literal>true</literal>/<literal>t</literal>/<literal>on</literal>/<literal>1</literal> or
<literal>no</literal>/<literal>n</literal>/<literal>false</literal>/<literal>f</literal>/<literal>off</literal>/<literal>0</literal>.
</para>
</refsect1>
-23
View File
@@ -23,28 +23,12 @@
#define _packed_ __attribute__((__packed__))
#define _malloc_ __attribute__((__malloc__))
#define _weak_ __attribute__((__weak__))
#define _likely_(x) (__builtin_expect(!!(x), 1))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
#define _public_ __attribute__((__visibility__("default")))
#define _hidden_ __attribute__((__visibility__("hidden")))
#define _weakref_(x) __attribute__((__weakref__(#x)))
#define _alignas_(x) __attribute__((__aligned__(__alignof(x))))
#define _alignptr_ __attribute__((__aligned__(sizeof(void*))))
#define _warn_unused_result_ __attribute__((__warn_unused_result__))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
#else
#define _fallthrough_
#endif
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
* compiler versions */
#ifndef _noreturn_
#if __STDC_VERSION__ >= 201112L
#define _noreturn_ _Noreturn
#else
#define _noreturn_ __attribute__((__noreturn__))
#endif
#endif
#if !defined(HAS_FEATURE_MEMORY_SANITIZER)
# if defined(__has_feature)
@@ -209,13 +193,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) {
return m;
}
/*
* STRLEN - return the length of a string literal, minus the trailing NUL byte.
* Contrary to strlen(), this is a constant expression.
* @x: a string literal.
*/
#define STRLEN(x) (sizeof(""x"") - 1U)
/*
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
+15
View File
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#ifndef NDEBUG
#include <efi.h>
#include <efilib.h>
#include "util.h"
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) {
log_error_stall(L"systemd-boot assertion '%a' failed at %a:%u, function %a(). Halting.", expr, file, line, function);
for (;;)
uefi_call_wrapper(BS->Stall, 1, 60 * 1000 * 1000);
}
#endif
+162 -109
View File
@@ -72,6 +72,9 @@ typedef struct {
} Config;
static VOID cursor_left(UINTN *cursor, UINTN *first) {
assert(cursor);
assert(first);
if ((*cursor) > 0)
(*cursor)--;
else if ((*first) > 0)
@@ -84,6 +87,9 @@ static VOID cursor_right(
UINTN x_max,
UINTN len) {
assert(cursor);
assert(first);
if ((*cursor)+1 < x_max)
(*cursor)++;
else if ((*first) + (*cursor) < len)
@@ -100,6 +106,8 @@ static BOOLEAN line_edit(
UINTN size, len, first, cursor, clear;
BOOLEAN exit, enter;
assert(line_out);
if (!line_in)
line_in = L"";
size = StrLen(line_in) + 1024;
@@ -134,7 +142,7 @@ static BOOLEAN line_edit(
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, print);
uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos);
err = console_key_read(&key, TRUE);
err = console_key_read(&key, 0);
if (EFI_ERROR(err))
continue;
@@ -332,6 +340,8 @@ static BOOLEAN line_edit(
}
static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) {
assert(config);
if (key == 0)
return -1;
@@ -362,6 +372,9 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
_cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL;
UINTN x, y;
assert(config);
assert(loaded_image_path);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK);
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
@@ -387,7 +400,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
Print(L"OsIndicationsSupported: %d\n", indvar);
Print(L"\n--- press key ---\n\n");
console_key_read(&key, TRUE);
console_key_read(&key, 0);
Print(L"timeout: %u\n", config->timeout_sec);
if (config->timeout_sec_efivar >= 0)
@@ -432,7 +445,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
Print(L"LoaderEntryDefault: %s\n", defaultstr);
Print(L"\n--- press key ---\n\n");
console_key_read(&key, TRUE);
console_key_read(&key, 0);
for (UINTN i = 0; i < config->entry_count; i++) {
ConfigEntry *entry;
@@ -482,7 +495,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
entry->path, entry->next_name);
Print(L"\n--- press key ---\n\n");
console_key_read(&key, TRUE);
console_key_read(&key, 0);
}
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
@@ -493,6 +506,10 @@ static BOOLEAN menu_run(
ConfigEntry **chosen_entry,
CHAR16 *loaded_image_path) {
assert(config);
assert(chosen_entry);
assert(loaded_image_path);
EFI_STATUS err;
UINTN visible_max;
UINTN idx_highlight;
@@ -509,11 +526,10 @@ static BOOLEAN menu_run(
UINTN y_max;
CHAR16 *status;
CHAR16 *clearline;
INTN timeout_remain;
UINTN timeout_remain = config->timeout_sec;
INT16 idx;
BOOLEAN exit = FALSE;
BOOLEAN run = TRUE;
BOOLEAN wait = FALSE;
graphics_mode(FALSE);
uefi_call_wrapper(ST->ConIn->Reset, 2, ST->ConIn, FALSE);
@@ -527,7 +543,7 @@ static BOOLEAN menu_run(
err = console_set_mode(&config->console_mode, config->console_mode_change);
if (EFI_ERROR(err)) {
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
Print(L"Error switching console mode to %ld: %r.\r", (UINT64)config->console_mode, err);
log_error_stall(L"Error switching console mode to %lu: %r", (UINT64)config->console_mode, err);
}
} else
uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
@@ -538,12 +554,6 @@ static BOOLEAN menu_run(
y_max = 25;
}
/* we check 10 times per second for a keystroke */
if (config->timeout_sec > 0)
timeout_remain = config->timeout_sec * 10;
else
timeout_remain = -1;
idx_highlight = config->idx_default;
idx_highlight_prev = 0;
@@ -643,7 +653,7 @@ static BOOLEAN menu_run(
if (timeout_remain > 0) {
FreePool(status);
status = PoolPrint(L"Boot in %d sec.", (timeout_remain + 5) / 10);
status = PoolPrint(L"Boot in %d s.", timeout_remain);
}
/* print status at last line of screen */
@@ -664,27 +674,18 @@ static BOOLEAN menu_run(
uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, clearline+1 + x + len);
}
err = console_key_read(&key, wait);
if (EFI_ERROR(err)) {
/* timeout reached */
err = console_key_read(&key, timeout_remain > 0 ? 1000 * 1000 : 0);
if (err == EFI_TIMEOUT) {
timeout_remain--;
if (timeout_remain == 0) {
exit = TRUE;
break;
}
/* sleep and update status */
if (timeout_remain > 0) {
uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
timeout_remain--;
continue;
}
/* timeout disabled, wait for next key */
wait = TRUE;
/* update status */
continue;
}
timeout_remain = -1;
} else
timeout_remain = 0;
/* clear status after keystroke */
if (status) {
@@ -787,7 +788,7 @@ static BOOLEAN menu_run(
config->timeout_sec_efivar,
EFI_VARIABLE_NON_VOLATILE);
if (config->timeout_sec_efivar > 0)
status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar);
status = PoolPrint(L"Menu timeout set to %d s.", config->timeout_sec_efivar);
else
status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
} else if (config->timeout_sec_efivar <= 0){
@@ -795,7 +796,7 @@ static BOOLEAN menu_run(
efivar_set(
LOADER_GUID, L"LoaderConfigTimeout", NULL, EFI_VARIABLE_NON_VOLATILE);
if (config->timeout_sec_config > 0)
status = PoolPrint(L"Menu timeout of %d sec is defined by configuration file.",
status = PoolPrint(L"Menu timeout of %d s is defined by configuration file.",
config->timeout_sec_config);
else
status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
@@ -813,7 +814,7 @@ static BOOLEAN menu_run(
config->timeout_sec_efivar,
EFI_VARIABLE_NON_VOLATILE);
if (config->timeout_sec_efivar > 0)
status = PoolPrint(L"Menu timeout set to %d sec.",
status = PoolPrint(L"Menu timeout set to %d s.",
config->timeout_sec_efivar);
else
status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu.");
@@ -884,6 +885,9 @@ static BOOLEAN menu_run(
}
static VOID config_add_entry(Config *config, ConfigEntry *entry) {
assert(config);
assert(entry);
if ((config->entry_count & 15) == 0) {
UINTN i;
@@ -924,6 +928,12 @@ static CHAR8 *line_get_key_value(
CHAR8 *line, *value;
UINTN linelen;
assert(content);
assert(sep);
assert(pos);
assert(key_ret);
assert(value_ret);
skip:
line = content + *pos;
if (*line == '\0')
@@ -985,6 +995,10 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
CHAR8 *line;
UINTN pos = 0;
CHAR8 *key, *value;
EFI_STATUS err;
assert(config);
assert(content);
while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) {
if (strcmpa((CHAR8 *)"timeout", key) == 0) {
@@ -1004,32 +1018,23 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
}
if (strcmpa((CHAR8 *)"editor", key) == 0) {
BOOLEAN on;
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->editor = on;
err = parse_boolean(value, &config->editor);
if (EFI_ERROR(err))
log_error_stall(L"Error parsing 'editor' config option: %a", value);
continue;
}
if (strcmpa((CHAR8 *)"auto-entries", key) == 0) {
BOOLEAN on;
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->auto_entries = on;
err = parse_boolean(value, &config->auto_entries);
if (EFI_ERROR(err))
log_error_stall(L"Error parsing 'auto-entries' config option: %a", value);
continue;
}
if (strcmpa((CHAR8 *)"auto-firmware", key) == 0) {
BOOLEAN on;
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->auto_firmware = on;
err = parse_boolean(value, &config->auto_firmware);
if (EFI_ERROR(err))
log_error_stall(L"Error parsing 'auto-firmware' config option: %a", value);
continue;
}
@@ -1061,8 +1066,11 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
else {
BOOLEAN on;
if (EFI_ERROR(parse_boolean(value, &on)))
err = parse_boolean(value, &on);
if (EFI_ERROR(err)) {
log_error_stall(L"Error parsing 'random-seed-mode' config option: %a", value);
continue;
}
config->random_seed_mode = on ? RANDOM_SEED_ALWAYS : RANDOM_SEED_OFF;
}
@@ -1079,6 +1087,10 @@ static VOID config_entry_parse_tries(
UINTN left = UINTN_MAX, done = UINTN_MAX, factor = 1, i, next_left, next_done;
_cleanup_freepool_ CHAR16 *prefix = NULL;
assert(entry);
assert(path);
assert(file);
/*
* Parses a suffix of two counters (one going down, one going up) in the form "+LEFT-DONE" from the end of the
* filename (but before the .efi/.conf suffix), where the "-DONE" part is optional and may be left out (in
@@ -1196,6 +1208,9 @@ static VOID config_entry_bump_counters(
UINTN file_info_size, a, b;
EFI_STATUS r;
assert(entry);
assert(root_dir);
if (entry->tries_left == UINTN_MAX)
return;
@@ -1221,8 +1236,7 @@ static VOID config_entry_bump_counters(
break;
if (r != EFI_BUFFER_TOO_SMALL || file_info_size * 2 < file_info_size) {
Print(L"\nFailed to get file info for '%s': %r\n", old_path, r);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
log_error_stall(L"Failed to get file info for '%s': %r", old_path, r);
return;
}
@@ -1234,8 +1248,7 @@ static VOID config_entry_bump_counters(
StrCpy(file_info->FileName, entry->next_name);
r = uefi_call_wrapper(handle->SetInfo, 4, handle, &EfiFileInfoGuid, file_info_size, file_info);
if (EFI_ERROR(r)) {
Print(L"\nFailed to rename '%s' to '%s', ignoring: %r\n", old_path, entry->next_name, r);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
log_error_stall(L"Failed to rename '%s' to '%s', ignoring: %r", old_path, entry->next_name, r);
return;
}
@@ -1271,6 +1284,14 @@ static VOID config_entry_add_from_file(
EFI_FILE_HANDLE handle;
_cleanup_freepool_ CHAR16 *initrd = NULL;
assert(config);
assert(device);
assert(root_dir);
assert(path);
assert(file);
assert(content);
assert(loaded_image_path);
entry = AllocatePool(sizeof(ConfigEntry));
*entry = (ConfigEntry) {
@@ -1399,6 +1420,8 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
UINTN sec;
EFI_STATUS err;
assert(root_dir);
*config = (Config) {
.editor = TRUE,
.auto_entries = TRUE,
@@ -1436,6 +1459,11 @@ static VOID config_load_entries(
EFI_FILE_HANDLE entries_dir;
EFI_STATUS err;
assert(config);
assert(device);
assert(root_dir);
assert(loaded_image_path);
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &entries_dir, (CHAR16*) L"\\loader\\entries", EFI_FILE_MODE_READ, 0ULL);
if (!EFI_ERROR(err)) {
for (;;) {
@@ -1471,6 +1499,9 @@ static VOID config_load_entries(
static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
INTN r;
assert(a);
assert(b);
/* Order entries that have no tries left to the beginning of the list */
if (a->tries_left != 0 && b->tries_left == 0)
return 1;
@@ -1501,6 +1532,8 @@ static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) {
}
static VOID config_sort_entries(Config *config) {
assert(config);
for (UINTN i = 1; i < config->entry_count; i++) {
BOOLEAN more;
@@ -1522,6 +1555,9 @@ static VOID config_sort_entries(Config *config) {
}
static INTN config_entry_find(Config *config, CHAR16 *id) {
assert(config);
assert(id);
for (UINTN i = 0; i < config->entry_count; i++)
if (StrCmp(config->entries[i]->id, id) == 0)
return (INTN) i;
@@ -1534,6 +1570,8 @@ static VOID config_default_entry_select(Config *config) {
EFI_STATUS err;
INTN i;
assert(config);
/*
* The EFI variable to specify a boot entry for the next, and only the
* next reboot. The variable is always cleared directly after it is read.
@@ -1604,6 +1642,8 @@ static VOID config_default_entry_select(Config *config) {
static BOOLEAN find_nonunique(ConfigEntry **entries, UINTN entry_count) {
BOOLEAN non_unique = FALSE;
assert(entries);
for (UINTN i = 0; i < entry_count; i++)
entries[i]->non_unique = FALSE;
@@ -1622,6 +1662,8 @@ static BOOLEAN find_nonunique(ConfigEntry **entries, UINTN entry_count) {
/* generate a unique title, avoiding non-distinguishable menu entries */
static VOID config_title_generate(Config *config) {
assert(config);
/* set title */
for (UINTN i = 0; i < config->entry_count; i++) {
CHAR16 *title;
@@ -1694,6 +1736,11 @@ static BOOLEAN config_entry_add_call(
ConfigEntry *entry;
assert(config);
assert(id);
assert(title);
assert(call);
entry = AllocatePool(sizeof(ConfigEntry));
*entry = (ConfigEntry) {
.id = StrDuplicate(id),
@@ -1720,11 +1767,17 @@ static ConfigEntry *config_entry_add_loader(
ConfigEntry *entry;
assert(config);
assert(device);
assert(id);
assert(title);
assert(loader);
entry = AllocatePool(sizeof(ConfigEntry));
*entry = (ConfigEntry) {
.type = type,
.title = StrDuplicate(title),
.version = StrDuplicate(version),
.version = version ? StrDuplicate(version) : NULL,
.device = device,
.loader = StrDuplicate(loader),
.id = StrDuplicate(id),
@@ -1753,6 +1806,13 @@ static BOOLEAN config_entry_add_loader_auto(
ConfigEntry *entry;
EFI_STATUS err;
assert(config);
assert(device);
assert(root_dir);
assert(id);
assert(title);
assert(loader);
if (!config->auto_entries)
return FALSE;
@@ -1793,6 +1853,8 @@ static VOID config_entry_add_osx(Config *config) {
UINTN handle_count = 0;
_cleanup_freepool_ EFI_HANDLE *handles = NULL;
assert(config);
if (!config->auto_entries)
return;
@@ -1823,6 +1885,10 @@ static VOID config_entry_add_linux(
EFI_STATUS err;
ConfigEntry *entry;
assert(config);
assert(device);
assert(root_dir);
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &linux_dir, (CHAR16*) L"\\EFI\\Linux", EFI_FILE_MODE_READ, 0ULL);
if (EFI_ERROR(err))
return;
@@ -1957,6 +2023,9 @@ static EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node
EFI_DEVICE_PATH *parent;
UINTN len;
assert(path);
assert(node);
len = (UINT8*) NextDevicePathNode(node) - (UINT8*) path;
parent = (EFI_DEVICE_PATH*) AllocatePool(len + sizeof(EFI_DEVICE_PATH));
CopyMem(parent, path, len);
@@ -1978,6 +2047,9 @@ static VOID config_load_xbootldr(
EFI_FILE *root_dir;
EFI_STATUS r;
assert(config);
assert(device);
partition_path = DevicePathFromHandle(device);
if (!partition_path)
return;
@@ -2164,19 +2236,16 @@ static EFI_STATUS image_start(
CHAR16 *options;
EFI_STATUS err;
assert(config);
assert(entry);
path = FileDevicePath(entry->device, entry->loader);
if (!path) {
Print(L"Error getting device path.");
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return EFI_INVALID_PARAMETER;
}
if (!path)
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Error getting device path.");
err = uefi_call_wrapper(BS->LoadImage, 6, FALSE, parent_image, path, NULL, 0, &image);
if (EFI_ERROR(err)) {
Print(L"Error loading %s: %r", entry->loader, err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error loading %s: %r", entry->loader, err);
if (config->options_edit)
options = config->options_edit;
@@ -2190,22 +2259,19 @@ static EFI_STATUS image_start(
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err)) {
Print(L"Error getting LoadedImageProtocol handle: %r", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
log_error_stall(L"Error getting LoadedImageProtocol handle: %r", err);
goto out_unload;
}
loaded_image->LoadOptions = options;
loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16);
loaded_image->LoadOptionsSize = StrSize(loaded_image->LoadOptions);
#if ENABLE_TPM
/* Try to log any options to the TPM, especially to catch manually edited options */
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
if (EFI_ERROR(err)) {
Print(L"Unable to add image options measurement: %r", err);
uefi_call_wrapper(BS->Stall, 1, 200 * 1000);
}
if (EFI_ERROR(err))
log_error_stall(L"Unable to add image options measurement: %r", err);
#endif
}
@@ -2231,12 +2297,11 @@ static EFI_STATUS reboot_into_firmware(VOID) {
return err;
err = uefi_call_wrapper(RT->ResetSystem, 4, EfiResetCold, EFI_SUCCESS, 0, NULL);
Print(L"Error calling ResetSystem: %r", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
return log_error_status_stall(err, L"Error calling ResetSystem: %r", err);
}
static VOID config_free(Config *config) {
assert(config);
for (UINTN i = 0; i < config->entry_count; i++)
config_entry_free(config->entries[i]);
FreePool(config->entries);
@@ -2246,26 +2311,30 @@ static VOID config_free(Config *config) {
}
static VOID config_write_entries_to_variable(Config *config) {
_cleanup_freepool_ CHAR16 *buffer = NULL;
_cleanup_freepool_ CHAR8 *buffer = NULL;
UINTN sz = 0;
CHAR16 *p;
CHAR8 *p;
assert(config);
for (UINTN i = 0; i < config->entry_count; i++)
sz += StrLen(config->entries[i]->id) + 1;
sz += StrSize(config->entries[i]->id);
p = buffer = AllocatePool(sz * sizeof(CHAR16));
p = buffer = AllocatePool(sz);
for (UINTN i = 0; i < config->entry_count; i++) {
UINTN l;
l = StrLen(config->entries[i]->id) + 1;
CopyMem(p, config->entries[i]->id, l * sizeof(CHAR16));
l = StrSize(config->entries[i]->id);
CopyMem(p, config->entries[i]->id, l);
p += l;
}
assert(p == buffer + sz);
/* Store the full list of discovered entries. */
(void) efivar_set_raw(LOADER_GUID, L"LoaderEntries", buffer, (UINT8 *) p - (UINT8 *) buffer, 0);
(void) efivar_set_raw(LOADER_GUID, L"LoaderEntries", buffer, sz, 0);
}
EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
@@ -2305,30 +2374,21 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err)) {
Print(L"Error getting a LoadedImageProtocol handle: %r", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
/* export the device path this image is started from */
if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
efivar_set(LOADER_GUID, L"LoaderDevicePartUUID", uuid, 0);
root_dir = LibOpenRoot(loaded_image->DeviceHandle);
if (!root_dir) {
Print(L"Unable to open root directory.");
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return EFI_LOAD_ERROR;
}
if (!root_dir)
return log_error_status_stall(EFI_LOAD_ERROR, L"Unable to open root directory.", EFI_LOAD_ERROR);
if (secure_boot_enabled() && shim_loaded()) {
err = security_policy_install();
if (EFI_ERROR(err)) {
Print(L"Error installing security policy: %r ", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error installing security policy: %r", err);
}
/* the filesystem path to this image, to prevent adding ourselves to the menu */
@@ -2367,8 +2427,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
}
if (config.entry_count == 0) {
Print(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
log_error_stall(L"No loader found. Configuration files in \\loader\\entries\\*.conf are needed.");
goto out;
}
@@ -2392,13 +2451,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
else {
UINT64 key;
err = console_key_read(&key, FALSE);
if (err == EFI_NOT_READY) {
uefi_call_wrapper(BS->Stall, 1, 100 * 1000);
err = console_key_read(&key, FALSE);
}
/* Block up to 100ms to give firmware time to get input working. */
err = console_key_read(&key, 100 * 1000);
if (!EFI_ERROR(err)) {
INT16 idx;
@@ -2440,8 +2494,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
err = image_start(image, &config, entry);
if (EFI_ERROR(err)) {
graphics_mode(FALSE);
Print(L"\nFailed to execute %s (%s): %r\n", entry->title, entry->loader, err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
log_error_stall(L"Failed to execute %s (%s): %r", entry->title, entry->loader, err);
goto out;
}
+79 -29
View File
@@ -11,61 +11,107 @@
#define EFI_SIMPLE_TEXT_INPUT_EX_GUID &(EFI_GUID) EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID
EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) {
static inline void EventClosep(EFI_EVENT *event) {
if (!*event)
return;
uefi_call_wrapper(BS->CloseEvent, 1, *event);
}
/*
* Reading input from the console sounds like an easy task to do, but thanks to broken
* firmware it is actually a nightmare.
*
* There is a ConIn and TextInputEx API for this. Ideally we want to use TextInputEx,
* because that gives us Ctrl/Alt/Shift key state information. Unfortunately, it is not
* always available and sometimes just non-functional.
*
* On the other hand we have ConIn, where some firmware likes to just freeze on us
* if we call ReadKeyStroke on it.
*
* Therefore, we use WaitForEvent on both ConIn and TextInputEx (if available) along
* with a timer event. The timer ensures there is no need to call into functions
* that might freeze on us, while still allowing us to show a timeout counter.
*/
EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec) {
static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx;
static BOOLEAN checked;
UINTN index;
EFI_INPUT_KEY k;
EFI_STATUS err;
_cleanup_(EventClosep) EFI_EVENT timer = NULL;
EFI_EVENT events[3] = { ST->ConIn->WaitForKey };
UINTN n_events = 1;
assert(key);
if (!checked) {
err = LibLocateProtocol(EFI_SIMPLE_TEXT_INPUT_EX_GUID, (VOID **)&TextInputEx);
if (EFI_ERROR(err))
if (EFI_ERROR(err) ||
uefi_call_wrapper(BS->CheckEvent, 1, TextInputEx->WaitForKeyEx) == EFI_INVALID_PARAMETER)
/* If WaitForKeyEx fails here, the firmware pretends it talks this
* protocol, but it really doesn't. */
TextInputEx = NULL;
else
events[n_events++] = TextInputEx->WaitForKeyEx;
checked = TRUE;
}
/* wait until key is pressed */
if (wait)
uefi_call_wrapper(BS->WaitForEvent, 3, 1, &ST->ConIn->WaitForKey, &index);
if (timeout_usec > 0) {
err = uefi_call_wrapper(BS->CreateEvent, 5, EVT_TIMER, 0, NULL, NULL, &timer);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error creating timer event: %r", err);
if (TextInputEx) {
EFI_KEY_DATA keydata;
UINT64 keypress;
/* SetTimer expects 100ns units for some reason. */
err = uefi_call_wrapper(BS->SetTimer, 3, timer, TimerRelative, timeout_usec * 10);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error arming timer event: %r", err);
events[n_events++] = timer;
}
err = uefi_call_wrapper(BS->WaitForEvent, 3, n_events, events, &index);
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error waiting for events: %r", err);
if (timeout_usec > 0 && timer == events[index])
return EFI_TIMEOUT;
/* TextInputEx might be ready too even if ConIn got to signal first. */
if (TextInputEx && !EFI_ERROR(uefi_call_wrapper(BS->CheckEvent, 1, TextInputEx->WaitForKeyEx))) {
EFI_KEY_DATA keydata;
UINT64 keypress;
UINT32 shift = 0;
err = uefi_call_wrapper(TextInputEx->ReadKeyStrokeEx, 2, TextInputEx, &keydata);
if (!EFI_ERROR(err)) {
UINT32 shift = 0;
if (EFI_ERROR(err))
return err;
/* do not distinguish between left and right keys */
if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) {
if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED))
shift |= EFI_CONTROL_PRESSED;
if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED))
shift |= EFI_ALT_PRESSED;
};
/* do not distinguish between left and right keys */
if (keydata.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) {
if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED))
shift |= EFI_CONTROL_PRESSED;
if (keydata.KeyState.KeyShiftState & (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED))
shift |= EFI_ALT_PRESSED;
};
/* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar);
if (keypress > 0) {
*key = keypress;
return 0;
}
/* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */
keypress = KEYPRESS(shift, keydata.Key.ScanCode, keydata.Key.UnicodeChar);
if (keypress > 0) {
*key = keypress;
return EFI_SUCCESS;
}
return EFI_NOT_READY;
}
/* fallback for firmware which does not support SimpleTextInputExProtocol
*
* This is also called in case ReadKeyStrokeEx did not return a key, because
* some broken firmwares offer SimpleTextInputExProtocol, but never actually
* handle any key. */
err = uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2, ST->ConIn, &k);
if (EFI_ERROR(err))
return err;
*key = KEYPRESS(0, k.ScanCode, k.UnicodeChar);
return 0;
return EFI_SUCCESS;
}
static EFI_STATUS change_mode(UINTN mode) {
@@ -108,6 +154,8 @@ static EFI_STATUS mode_auto(UINTN *mode) {
EFI_STATUS err;
BOOLEAN keep = FALSE;
assert(mode);
err = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
if (!EFI_ERROR(err) && GraphicsOutput->Mode && GraphicsOutput->Mode->Info) {
Info = GraphicsOutput->Mode->Info;
@@ -156,6 +204,8 @@ static EFI_STATUS mode_auto(UINTN *mode) {
}
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how) {
assert(mode);
if (how == CONSOLE_MODE_AUTO)
return mode_auto(mode);
+1 -1
View File
@@ -16,5 +16,5 @@ enum console_mode_change_type {
CONSOLE_MODE_MAX,
};
EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait);
EFI_STATUS console_key_read(UINT64 *key, UINT64 timeout_usec);
EFI_STATUS console_set_mode(UINTN *mode, enum console_mode_change_type how);
+5
View File
@@ -42,6 +42,7 @@
*/
#include "crc32.h"
#include "macro-fundamental.h"
static const UINT32 crc32_tab[] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
@@ -111,6 +112,8 @@ UINT32 crc32(UINT32 seed, const VOID *buf, UINTN len) {
const UINT8 *p = buf;
UINT32 crc = seed;
assert(buf);
while (len > 0) {
crc = crc32_add_char(crc, *p++);
len--;
@@ -129,6 +132,8 @@ UINT32 crc32_exclude_offset(
const UINT8 *p = buf;
UINT32 crc = seed;
assert(buf);
for (UINTN i = 0; i < len; i++) {
UINT8 x = *p++;
+2
View File
@@ -9,6 +9,8 @@
EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[static 37]) {
EFI_DEVICE_PATH *device_path;
assert(handle);
/* export the device path this image is started from */
device_path = DevicePathFromHandle(handle);
if (device_path) {
+5
View File
@@ -17,6 +17,8 @@ static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
handover_f handover;
UINTN start = (UINTN)params->hdr.code32_start;
assert(params);
#ifdef __x86_64__
asm volatile ("cli");
start += 512;
@@ -35,6 +37,9 @@ EFI_STATUS linux_exec(EFI_HANDLE *image,
EFI_PHYSICAL_ADDRESS addr;
EFI_STATUS err;
assert(image);
assert(cmdline);
image_params = (struct boot_params *) linux_addr;
if (image_params->hdr.boot_flag != 0xAA55 ||
+11 -4
View File
@@ -5,6 +5,7 @@
#include <efi.h>
#include <efilib.h>
#include "macro-fundamental.h"
#include "measure.h"
#define EFI_TCG_GUID \
@@ -184,8 +185,10 @@ static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 p
EFI_PHYSICAL_ADDRESS event_log_last;
UINTN desc_len;
desc_len = (StrLen(description) + 1) * sizeof(CHAR16);
assert(tcg);
assert(description);
desc_len = StrSize(description);
tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT));
if (!tcg_event)
@@ -215,14 +218,16 @@ static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32
EFI_TCG2_EVENT *tcg_event;
UINTN desc_len;
desc_len = StrLen(description) * sizeof(CHAR16);
assert(tcg);
assert(description);
tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1);
desc_len = StrSize(description);
tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len);
if (!tcg_event)
return EFI_OUT_OF_RESOURCES;
tcg_event->Size = sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1;
tcg_event->Size = sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len;
tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
tcg_event->Header.PCRIndex = pcrindex;
@@ -302,6 +307,8 @@ EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UIN
EFI_TCG *tpm1;
EFI_TCG2 *tpm2;
assert(description);
tpm2 = tcg2_interface_check();
if (tpm2)
return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
+7 -2
View File
@@ -17,6 +17,7 @@ efi_headers = files('''
'''.split())
common_sources = '''
assert.c
disk.c
graphics.c
measure.c
@@ -219,12 +220,16 @@ if have_gnu_efi
compile_args += ['-Werror']
endif
if get_option('buildtype') == 'debug'
compile_args += ['-ggdb', '-O0']
compile_args += ['-ggdb', '-O0', '-DEFI_DEBUG']
elif get_option('buildtype') == 'debugoptimized'
compile_args += ['-ggdb', '-Og']
compile_args += ['-ggdb', '-Og', '-DEFI_DEBUG']
else
compile_args += ['-O2']
endif
if get_option('b_ndebug') == 'true' or (
get_option('b_ndebug') == 'if-release' and ['plain', 'release'].contains(get_option('buildtype')))
compile_args += ['-DNDEBUG']
endif
efi_ldflags = ['-T', efi_lds,
'-shared',
+6
View File
@@ -66,6 +66,9 @@ EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs
struct PeHeader *pe;
UINTN offset;
assert(base);
assert(sections);
dos = (struct DosFileHeader *)base;
if (CompareMem(dos->Magic, "MZ", 2) != 0)
@@ -118,6 +121,9 @@ EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, CHAR8 **sections
EFI_STATUS err;
_cleanup_freepool_ CHAR8 *header = NULL;
assert(dir);
assert(path);
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, path, EFI_FILE_MODE_READ, 0ULL);
if (EFI_ERROR(err))
return err;
+48 -53
View File
@@ -22,6 +22,8 @@ static EFI_STATUS acquire_rng(UINTN size, VOID **ret) {
EFI_RNG_PROTOCOL *rng;
EFI_STATUS err;
assert(ret);
/* Try to acquire the specified number of bytes from the UEFI RNG */
err = LibLocateProtocol(EFI_RNG_GUID, (VOID**) &rng);
@@ -35,10 +37,8 @@ static EFI_STATUS acquire_rng(UINTN size, VOID **ret) {
return log_oom();
err = uefi_call_wrapper(rng->GetRNG, 3, rng, NULL, size, data);
if (EFI_ERROR(err)) {
Print(L"Failed to acquire RNG data: %r\n", err);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to acquire RNG data: %r", err);
*ret = TAKE_PTR(data);
return EFI_SUCCESS;
@@ -65,6 +65,10 @@ static VOID hash_once(
struct sha256_ctx hash;
assert(old_seed);
assert(rng);
assert(system_token);
sha256_init_ctx(&hash);
sha256_process_bytes(old_seed, size, &hash);
if (rng)
@@ -87,6 +91,11 @@ static EFI_STATUS hash_many(
_cleanup_freepool_ VOID *output = NULL;
assert(old_seed);
assert(rng);
assert(system_token);
assert(ret);
/* Hashes the specified parameters in counter mode, generating n hash values, with the counter in the
* range counter_start…counter_start+n-1. */
@@ -117,6 +126,12 @@ static EFI_STATUS mangle_random_seed(
EFI_STATUS err;
UINTN n;
assert(old_seed);
assert(rng);
assert(system_token);
assert(ret_new_seed);
assert(ret_for_kernel);
/* This takes the old seed file contents, an (optional) random number acquired from the UEFI RNG, an
* (optional) system 'token' installed once by the OS installer in an EFI variable, and hashes them
* together in counter mode, generating a new seed (to replace the file on disk) and the seed for the
@@ -146,17 +161,18 @@ static EFI_STATUS acquire_system_token(VOID **ret, UINTN *ret_size) {
EFI_STATUS err;
UINTN size;
assert(ret);
assert(ret_size);
err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size);
if (EFI_ERROR(err)) {
if (err != EFI_NOT_FOUND)
Print(L"Failed to read LoaderSystemToken EFI variable: %r", err);
log_error_stall(L"Failed to read LoaderSystemToken EFI variable: %r", err);
return err;
}
if (size <= 0) {
Print(L"System token too short, ignoring.");
return EFI_NOT_FOUND;
}
if (size <= 0)
return log_error_status_stall(EFI_NOT_FOUND, L"System token too short, ignoring.");
*ret = TAKE_PTR(data);
*ret_size = size;
@@ -166,7 +182,7 @@ static EFI_STATUS acquire_system_token(VOID **ret, UINTN *ret_size) {
static VOID validate_sha256(void) {
#ifndef __OPTIMIZE__
#ifdef EFI_DEBUG
/* Let's validate our SHA256 implementation. We stole it from glibc, and converted it to UEFI
* style. We better check whether it does the right stuff. We use the simpler test vectors from the
* SHA spec. Note that we strip this out in optimization builds. */
@@ -208,14 +224,9 @@ static VOID validate_sha256(void) {
sha256_process_bytes(array[i].string, strlena((const CHAR8*) array[i].string), &hash);
sha256_finish_ctx(&hash, result);
if (CompareMem(result, array[i].hash, HASH_VALUE_SIZE) != 0) {
Print(L"SHA256 failed validation.\n");
uefi_call_wrapper(BS->Stall, 1, 120 * 1000 * 1000);
return;
}
assert(CompareMem(result, array[i].hash, HASH_VALUE_SIZE) == 0);
}
Print(L"SHA256 validated\n");
#endif
}
@@ -226,6 +237,8 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
EFI_STATUS err;
assert(root_dir);
validate_sha256();
if (mode == RANDOM_SEED_OFF)
@@ -246,7 +259,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, (CHAR16*) L"\\loader\\random-seed", EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
if (EFI_ERROR(err)) {
if (err != EFI_NOT_FOUND && err != EFI_WRITE_PROTECTED)
Print(L"Failed to open random seed file: %r\n", err);
log_error_stall(L"Failed to open random seed file: %r", err);
return err;
}
@@ -255,15 +268,11 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
return log_oom();
size = info->FileSize;
if (size < RANDOM_MAX_SIZE_MIN) {
Print(L"Random seed file is too short?\n");
return EFI_INVALID_PARAMETER;
}
if (size < RANDOM_MAX_SIZE_MIN)
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too short.");
if (size > RANDOM_MAX_SIZE_MAX) {
Print(L"Random seed file is too large?\n");
return EFI_INVALID_PARAMETER;
}
if (size > RANDOM_MAX_SIZE_MAX)
return log_error_status_stall(EFI_INVALID_PARAMETER, L"Random seed file is too large.");
seed = AllocatePool(size);
if (!seed)
@@ -271,20 +280,14 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
rsize = size;
err = uefi_call_wrapper(handle->Read, 3, handle, &rsize, seed);
if (EFI_ERROR(err)) {
Print(L"Failed to read random seed file: %r\n", err);
return err;
}
if (rsize != size) {
Print(L"Short read on random seed file\n");
return EFI_PROTOCOL_ERROR;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to read random seed file: %r", err);
if (rsize != size)
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short read on random seed file.");
err = uefi_call_wrapper(handle->SetPosition, 2, handle, 0);
if (EFI_ERROR(err)) {
Print(L"Failed to seek to beginning of random seed file: %r\n", err);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to seek to beginning of random seed file: %r", err);
/* Request some random data from the UEFI RNG. We don't need this to work safely, but it's a good
* idea to use it because it helps us for cases where users mistakenly include a random seed in
@@ -299,27 +302,19 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
/* Update the random seed on disk before we use it */
wsize = size;
err = uefi_call_wrapper(handle->Write, 3, handle, &wsize, new_seed);
if (EFI_ERROR(err)) {
Print(L"Failed to write random seed file: %r\n", err);
return err;
}
if (wsize != size) {
Print(L"Short write on random seed file\n");
return EFI_PROTOCOL_ERROR;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to write random seed file: %r", err);
if (wsize != size)
return log_error_status_stall(EFI_PROTOCOL_ERROR, L"Short write on random seed file.");
err = uefi_call_wrapper(handle->Flush, 1, handle);
if (EFI_ERROR(err)) {
Print(L"Failed to flush random seed file: %r\n");
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to flush random seed file: %r", err);
/* We are good to go */
err = efivar_set_raw(LOADER_GUID, L"LoaderRandomSeed", for_kernel, size, 0);
if (EFI_ERROR(err)) {
Print(L"Failed to write random seed to EFI variable: %r\n", err);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Failed to write random seed to EFI variable: %r", err);
return EFI_SUCCESS;
}
+13
View File
@@ -23,6 +23,7 @@
/* Written by Ulrich Drepper <drepper@redhat.com>, 2007. */
#include "macro-fundamental.h"
#include "sha256.h"
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
@@ -73,6 +74,8 @@ static void sha256_process_block(const void *, UINTN, struct sha256_ctx *);
/* Initialize structure containing state of computation.
(FIPS 180-2:5.3.2) */
void sha256_init_ctx(struct sha256_ctx *ctx) {
assert(ctx);
ctx->H[0] = 0x6a09e667;
ctx->H[1] = 0xbb67ae85;
ctx->H[2] = 0x3c6ef372;
@@ -96,6 +99,9 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
UINT32 bytes = ctx->buflen;
UINTN pad;
assert(ctx);
assert(resbuf);
/* Now count remaining bytes. */
ctx->total64 += bytes;
@@ -118,6 +124,9 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
}
void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) {
assert(buffer);
assert(ctx);
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
@@ -191,6 +200,10 @@ void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx)
static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ctx *ctx) {
const UINT32 *words = buffer;
UINTN nwords = len / sizeof (UINT32);
assert(buffer);
assert(ctx);
UINT32 a = ctx->H[0];
UINT32 b = ctx->H[1];
UINT32 c = ctx->H[2];
+7
View File
@@ -111,6 +111,10 @@ static EFIAPI EFI_STATUS security2_policy_authentication (const EFI_SECURITY2_PR
VOID *file_buffer, UINTN file_size, BOOLEAN boot_policy) {
EFI_STATUS status;
assert(this);
assert(device_path);
assert(file_buffer);
/* Chain original security policy */
status = uefi_call_wrapper(es2fa, 5, this, device_path, file_buffer, file_size, boot_policy);
@@ -143,6 +147,9 @@ static EFIAPI EFI_STATUS security_policy_authentication (const EFI_SECURITY_PROT
_cleanup_freepool_ CHAR8 *file_buffer = NULL;
UINTN file_size;
assert(this);
assert(device_path_const);
if (!device_path_const)
return EFI_INVALID_PARAMETER;
+14
View File
@@ -44,6 +44,11 @@ static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_
struct bmp_map *map;
UINTN row_size;
assert(bmp);
assert(ret_dib);
assert(ret_map);
assert(pixmap);
if (size < sizeof(struct bmp_file) + sizeof(struct bmp_dib))
return EFI_INVALID_PARAMETER;
@@ -128,6 +133,8 @@ static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_
static VOID pixel_blend(UINT32 *dst, const UINT32 source) {
UINT32 alpha, src, src_rb, src_g, dst_rb, dst_g, rb, g;
assert(dst);
alpha = (source & 0xff);
/* convert src from RGBA to XRGB */
@@ -152,6 +159,11 @@ static EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf,
UINT8 *pixmap) {
UINT8 *in;
assert(buf);
assert(dib);
assert(map);
assert(pixmap);
/* transform and copy pixels */
in = pixmap;
for (UINTN y = 0; y < dib->y; y++) {
@@ -247,6 +259,8 @@ EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_
UINTN y_pos = 0;
EFI_STATUS err;
assert(content);
if (!background) {
if (StriCmp(L"Apple", ST->FirmwareVendor) == 0) {
pixel.Red = 0xc0;
+7 -17
View File
@@ -36,18 +36,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image,
image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
if (EFI_ERROR(err)) {
Print(L"Error getting a LoadedImageProtocol handle: %r ", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Error getting a LoadedImageProtocol handle: %r", err);
err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, offs, szs);
if (EFI_ERROR(err)) {
Print(L"Unable to locate embedded .linux section: %r ", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
}
if (EFI_ERROR(err))
return log_error_status_stall(err, L"Unable to locate embedded .linux section: %r", err);
if (szs[0] > 0)
cmdline = (CHAR8 *)(loaded_image->ImageBase) + addrs[0];
@@ -72,10 +66,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
if (EFI_ERROR(err)) {
Print(L"Unable to add image options measurement: %r", err);
uefi_call_wrapper(BS->Stall, 1, 200 * 1000);
}
if (EFI_ERROR(err))
log_error_stall(L"Unable to add image options measurement: %r", err);
#endif
}
@@ -126,7 +118,5 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
(UINTN)loaded_image->ImageBase + addrs[2], szs[2]);
graphics_mode(FALSE);
Print(L"Execution of embedded linux image failed: %r\n", err);
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return err;
return log_error_status_stall(err, L"Execution of embedded linux image failed: %r", err);
}
+86 -15
View File
@@ -67,13 +67,17 @@ UINT64 time_usec(VOID) {
}
EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) {
assert(b);
if (!v)
return EFI_INVALID_PARAMETER;
if (strcmpa(v, (CHAR8 *)"1") == 0 ||
strcmpa(v, (CHAR8 *)"yes") == 0 ||
strcmpa(v, (CHAR8 *)"y") == 0 ||
strcmpa(v, (CHAR8 *)"true") == 0) {
strcmpa(v, (CHAR8 *)"true") == 0 ||
strcmpa(v, (CHAR8 *)"t") == 0 ||
strcmpa(v, (CHAR8 *)"on") == 0) {
*b = TRUE;
return EFI_SUCCESS;
}
@@ -81,7 +85,9 @@ EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) {
if (strcmpa(v, (CHAR8 *)"0") == 0 ||
strcmpa(v, (CHAR8 *)"no") == 0 ||
strcmpa(v, (CHAR8 *)"n") == 0 ||
strcmpa(v, (CHAR8 *)"false") == 0) {
strcmpa(v, (CHAR8 *)"false") == 0 ||
strcmpa(v, (CHAR8 *)"f") == 0 ||
strcmpa(v, (CHAR8 *)"off") == 0) {
*b = FALSE;
return EFI_SUCCESS;
}
@@ -90,24 +96,37 @@ EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) {
}
EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, UINT32 flags) {
assert(vendor);
assert(name);
assert(buf || size == 0);
flags |= EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
return uefi_call_wrapper(RT->SetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, flags, size, (VOID*) buf);
}
EFI_STATUS efivar_set(const EFI_GUID *vendor, const CHAR16 *name, const CHAR16 *value, UINT32 flags) {
return efivar_set_raw(vendor, name, value, value ? (StrLen(value) + 1) * sizeof(CHAR16) : 0, flags);
assert(vendor);
assert(name);
return efivar_set_raw(vendor, name, value, value ? StrSize(value) : 0, flags);
}
EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UINTN i, UINT32 flags) {
CHAR16 str[32];
SPrint(str, 32, L"%u", i);
assert(vendor);
assert(name);
SPrint(str, ELEMENTSOF(str), L"%u", i);
return efivar_set(vendor, name, str, flags);
}
EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const CHAR16 *name, UINT32 value, UINT32 flags) {
UINT8 buf[4];
assert(vendor);
assert(name);
buf[0] = (UINT8)(value >> 0U & 0xFF);
buf[1] = (UINT8)(value >> 8U & 0xFF);
buf[2] = (UINT8)(value >> 16U & 0xFF);
@@ -119,6 +138,9 @@ EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, const CHAR16 *name, UINT
EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT64 value, UINT32 flags) {
UINT8 buf[8];
assert(vendor);
assert(name);
buf[0] = (UINT8)(value >> 0U & 0xFF);
buf[1] = (UINT8)(value >> 8U & 0xFF);
buf[2] = (UINT8)(value >> 16U & 0xFF);
@@ -132,35 +154,38 @@ EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT
}
EFI_STATUS efivar_get(const EFI_GUID *vendor, const CHAR16 *name, CHAR16 **value) {
_cleanup_freepool_ CHAR8 *buf = NULL;
_cleanup_freepool_ CHAR16 *buf = NULL;
EFI_STATUS err;
CHAR16 *val;
UINTN size;
err = efivar_get_raw(vendor, name, &buf, &size);
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, (CHAR8**)&buf, &size);
if (EFI_ERROR(err))
return err;
/* Make sure there are no incomplete characters in the buffer */
if ((size % 2) != 0)
if ((size % sizeof(CHAR16)) != 0)
return EFI_INVALID_PARAMETER;
if (!value)
return EFI_SUCCESS;
/* Return buffer directly if it happens to be NUL terminated already */
if (size >= 2 && buf[size-2] == 0 && buf[size-1] == 0) {
*value = (CHAR16*) TAKE_PTR(buf);
if (size >= sizeof(CHAR16) && buf[size/sizeof(CHAR16)] == 0) {
*value = TAKE_PTR(buf);
return EFI_SUCCESS;
}
/* Make sure a terminating NUL is available at the end */
val = AllocatePool(size + 2);
val = AllocatePool(size + sizeof(CHAR16));
if (!val)
return EFI_OUT_OF_RESOURCES;
CopyMem(val, buf, size);
val[size/2] = 0; /* NUL terminate */
val[size / sizeof(CHAR16)] = 0; /* NUL terminate */
*value = val;
return EFI_SUCCESS;
@@ -170,8 +195,12 @@ EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UI
_cleanup_freepool_ CHAR16 *val = NULL;
EFI_STATUS err;
assert(vendor);
assert(name);
assert(i);
err = efivar_get(vendor, name, &val);
if (!EFI_ERROR(err) && i)
if (!EFI_ERROR(err))
*i = Atoi(val);
return err;
@@ -182,6 +211,9 @@ EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const CHAR16 *name, UINT
UINTN size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, &buf, &size);
if (!EFI_ERROR(err) && ret) {
if (size != sizeof(UINT32))
@@ -199,6 +231,9 @@ EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT
UINTN size;
EFI_STATUS err;
assert(vendor);
assert(name);
err = efivar_get_raw(vendor, name, &buf, &size);
if (!EFI_ERROR(err) && ret) {
if (size != sizeof(UINT64))
@@ -217,6 +252,9 @@ EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **bu
UINTN l;
EFI_STATUS err;
assert(vendor);
assert(name);
l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE;
buf = AllocatePool(l);
if (!buf)
@@ -240,6 +278,10 @@ EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const CHAR16 *name, BOO
UINTN size;
EFI_STATUS err;
assert(vendor);
assert(name);
assert(ret);
err = efivar_get_raw(vendor, name, &b, &size);
if (!EFI_ERROR(err))
*ret = *b > 0;
@@ -250,12 +292,15 @@ EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const CHAR16 *name, BOO
VOID efivar_set_time_usec(const EFI_GUID *vendor, const CHAR16 *name, UINT64 usec) {
CHAR16 str[32];
assert(vendor);
assert(name);
if (usec == 0)
usec = time_usec();
if (usec == 0)
return;
SPrint(str, 32, L"%ld", usec);
SPrint(str, ELEMENTSOF(str), L"%ld", usec);
efivar_set(vendor, name, str, 0);
}
@@ -263,6 +308,9 @@ static INTN utf8_to_16(const CHAR8 *stra, CHAR16 *c) {
CHAR16 unichar;
UINTN len;
assert(stra);
assert(c);
if (!(stra[0] & 0x80))
len = 1;
else if ((stra[0] & 0xe0) == 0xc0)
@@ -316,6 +364,8 @@ CHAR16 *stra_to_str(const CHAR8 *stra) {
UINTN i;
CHAR16 *str;
assert(stra);
len = strlena(stra);
str = AllocatePool((len + 1) * sizeof(CHAR16));
@@ -344,6 +394,8 @@ CHAR16 *stra_to_path(const CHAR8 *stra) {
UINTN len;
UINTN i;
assert(stra);
len = strlena(stra);
str = AllocatePool((len + 2) * sizeof(CHAR16));
@@ -376,6 +428,7 @@ CHAR16 *stra_to_path(const CHAR8 *stra) {
}
CHAR8 *strchra(const CHAR8 *s, CHAR8 c) {
assert(s);
do {
if (*s == c)
return (CHAR8*) s;
@@ -388,6 +441,9 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
_cleanup_freepool_ CHAR8 *buf = NULL;
EFI_STATUS err;
assert(name);
assert(ret);
err = uefi_call_wrapper(dir->Open, 5, dir, &handle, (CHAR16*) name, EFI_FILE_MODE_READ, 0ULL);
if (EFI_ERROR(err))
return err;
@@ -425,8 +481,23 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
return err;
}
VOID log_error_stall(const CHAR16 *fmt, ...) {
va_list args;
assert(fmt);
uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTRED|EFI_BACKGROUND_BLACK);
Print(L"\n");
va_start(args, fmt);
VPrint(fmt, args);
va_end(args);
Print(L"\n");
uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
}
EFI_STATUS log_oom(void) {
Print(L"Out of memory.");
(void) uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
log_error_stall(L"Out of memory.");
return EFI_OUT_OF_RESOURCES;
}
+9
View File
@@ -74,4 +74,13 @@ static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) {
#define UINT64_MAX ((UINT64) -1)
#endif
VOID log_error_stall(const CHAR16 *fmt, ...);
EFI_STATUS log_oom(void);
/* This works just like log_error_errno() from userspace, but requires you
* to provide err a second time if you want to use %r in the message! */
#define log_error_status_stall(err, fmt, ...) \
({ \
log_error_stall(fmt, ##__VA_ARGS__); \
err; \
})
+31 -1
View File
@@ -14,6 +14,22 @@
#define _used_ __attribute__((__used__))
#define _unused_ __attribute__((__unused__))
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#define _likely_(x) (__builtin_expect(!!(x), 1))
#define _unlikely_(x) (__builtin_expect(!!(x), 0))
#if __GNUC__ >= 7
#define _fallthrough_ __attribute__((__fallthrough__))
#else
#define _fallthrough_
#endif
/* Define C11 noreturn without <stdnoreturn.h> and even on older gcc
* compiler versions */
#ifndef _noreturn_
#if __STDC_VERSION__ >= 201112L
#define _noreturn_ _Noreturn
#else
#define _noreturn_ __attribute__((__noreturn__))
#endif
#endif
#define XSTRINGIFY(x) #x
#define STRINGIFY(x) XSTRINGIFY(x)
@@ -34,7 +50,14 @@
#define CONCATENATE(x, y) XCONCATENATE(x, y)
#ifdef SD_BOOT
#define assert(expr) do {} while (false)
#ifdef NDEBUG
#define assert(expr)
#define assert_not_reached() __builtin_unreachable()
#else
void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_;
#define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); })
#define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__)
#endif
#endif
#if defined(static_assert)
@@ -233,3 +256,10 @@
(ptr) = NULL; \
_ptr_; \
})
/*
* STRLEN - return the length of a string literal, minus the trailing NUL byte.
* Contrary to strlen(), this is a constant expression.
* @x: a string literal.
*/
#define STRLEN(x) (sizeof(""x"") - sizeof(typeof(x[0])))
+2
View File
@@ -7,6 +7,8 @@
/* Do some basic checks on STRLEN() and DECIMAL_STR_MAX() */
assert_cc(STRLEN("xxx") == 3);
assert_cc(STRLEN("") == 0);
assert_cc(STRLEN(L"xxx") == 3 * sizeof(wchar_t));
assert_cc(STRLEN(L"") == 0);
assert_cc(DECIMAL_STR_MAX(uint8_t) == 5);
assert_cc(DECIMAL_STR_MAX(int8_t) == 5);
assert_cc(DECIMAL_STR_MAX(uint64_t) == 22);