Merge pull request #13137 from poettering/efi-random

beef up random seed logic, add boot loader entropy privisioning, improve docs about it
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2019-07-26 12:43:32 +02:00
committed by GitHub
33 changed files with 2239 additions and 214 deletions
+329 -68
View File
@@ -25,6 +25,7 @@
#include "copy.h"
#include "dirent-util.h"
#include "efivars.h"
#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@@ -34,6 +35,7 @@
#include "pager.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "random-util.h"
#include "rm-rf.h"
#include "stat-util.h"
#include "stdio-util.h"
@@ -580,21 +582,29 @@ static int mkdir_one(const char *prefix, const char *suffix) {
}
static const char *const esp_subdirs[] = {
/* The directories to place in the ESP */
"EFI",
"EFI/systemd",
"EFI/BOOT",
"loader",
/* Note that "/loader/entries" is not listed here, since it should be placed in $BOOT, which might
* not necessarily be the ESP */
NULL
};
static int create_esp_subdirs(const char *esp_path) {
static const char *const dollar_boot_subdirs[] = {
/* The directories to place in the XBOOTLDR partition or the ESP, depending what exists */
"loader",
"loader/entries", /* Type #1 entries */
"EFI",
"EFI/Linux", /* Type #2 entries */
NULL
};
static int create_subdirs(const char *root, const char * const *subdirs) {
const char *const *i;
int r;
STRV_FOREACH(i, esp_subdirs) {
r = mkdir_one(esp_path, *i);
STRV_FOREACH(i, subdirs) {
r = mkdir_one(root, *i);
if (r < 0)
return r;
}
@@ -603,6 +613,7 @@ static int create_esp_subdirs(const char *esp_path) {
}
static int copy_one_file(const char *esp_path, const char *name, bool force) {
const char *e;
char *p, *q;
int r;
@@ -610,13 +621,13 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
q = strjoina(esp_path, "/EFI/systemd/", name);
r = copy_file_with_version_check(p, q, force);
if (startswith(name, "systemd-boot")) {
e = startswith(name, "systemd-boot");
if (e) {
int k;
char *v;
/* Create the EFI default boot loader name (specified for removable devices) */
v = strjoina(esp_path, "/EFI/BOOT/BOOT",
name + STRLEN("systemd-boot"));
v = strjoina(esp_path, "/EFI/BOOT/BOOT", e);
ascii_strupper(strrchr(v, '/') + 1);
k = copy_file_with_version_check(p, v, force);
@@ -650,7 +661,7 @@ static int install_binaries(const char *esp_path, bool force) {
return r;
}
static bool same_entry(uint16_t id, const sd_id128_t uuid, const char *path) {
static bool same_entry(uint16_t id, sd_id128_t uuid, const char *path) {
_cleanup_free_ char *opath = NULL;
sd_id128_t ouuid;
int r;
@@ -864,19 +875,27 @@ static int rmdir_one(const char *prefix, const char *suffix) {
return 0;
}
static int remove_esp_subdirs(const char *esp_path) {
size_t i;
int r = 0;
static int remove_subdirs(const char *root, const char *const *subdirs) {
int r, q;
for (i = ELEMENTSOF(esp_subdirs)-1; i > 0; i--) {
int q;
/* We use recursion here to destroy the directories in reverse order. Which should be safe given how
* short the array is. */
q = rmdir_one(esp_path, esp_subdirs[i-1]);
if (q < 0 && r >= 0)
r = q;
}
if (!subdirs[0]) /* A the end of the list */
return 0;
return r;
r = remove_subdirs(root, subdirs + 1);
q = rmdir_one(root, subdirs[0]);
return r < 0 ? r : q;
}
static int remove_machine_id_directory(const char *root, sd_id128_t machine_id) {
char buf[SD_ID128_STRING_MAX];
assert(root);
return rmdir_one(root, sd_id128_to_string(machine_id, buf));
}
static int remove_binaries(const char *esp_path) {
@@ -893,26 +912,22 @@ static int remove_binaries(const char *esp_path) {
return r;
}
static int remove_loader_config(const char *esp_path) {
static int remove_file(const char *root, const char *file) {
const char *p;
assert(esp_path);
assert(root);
assert(file);
p = prefix_roota(esp_path, "/loader/loader.conf");
p = prefix_roota(root, file);
if (unlink(p) < 0) {
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to unlink file \"%s\": %m", p);
if (errno != ENOENT)
return -errno;
} else
log_info("Removed \"%s\".", p);
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno,
"Failed to unlink file \"%s\": %m", p);
return 0;
}
return errno == ENOENT ? 0 : -errno;
}
static int remove_entries_directory(const char *dollar_boot_path) {
assert(dollar_boot_path);
return rmdir_one(dollar_boot_path, "/loader/entries");
log_info("Removed \"%s\".", p);
return 1;
}
static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
@@ -936,6 +951,35 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
return 0;
}
static int remove_loader_variables(void) {
const char *p;
int r = 0;
/* Remove all persistent loader variables we define */
FOREACH_STRING(p,
"LoaderConfigTimeout",
"LoaderConfigTimeoutOneShot",
"LoaderEntryDefault",
"LoaderEntryOneShot",
"LoaderSystemToken") {
int q;
q = efi_set_variable(EFI_VENDOR_LOADER, p, NULL, 0);
if (q == -ENOENT)
continue;
if (q < 0) {
log_warning_errno(q, "Failed to remove %s variable: %m", p);
if (r >= 0)
r = q;
} else
log_info("Removed EFI variable %s.", p);
}
return r;
}
static int install_loader_config(const char *esp_path, sd_id128_t machine_id) {
char machine_string[SD_ID128_STRING_MAX];
_cleanup_(unlink_and_freep) char *t = NULL;
@@ -975,21 +1019,12 @@ static int install_loader_config(const char *esp_path, sd_id128_t machine_id) {
return 1;
}
static int install_entries_directories(const char *dollar_boot_path, sd_id128_t machine_id) {
int r;
static int install_machine_id_directory(const char *root, sd_id128_t machine_id) {
char buf[SD_ID128_STRING_MAX];
assert(dollar_boot_path);
assert(root);
/* Both /loader/entries and the entry directories themselves should be located on the same
* partition. Also create the parent directory for entry directories, so that kernel-install
* knows where to put them. */
r = mkdir_one(dollar_boot_path, "loader/entries");
if (r < 0)
return r;
return mkdir_one(dollar_boot_path, sd_id128_to_string(machine_id, buf));
return mkdir_one(root, sd_id128_to_string(machine_id, buf));
}
static int help(int argc, char *argv[], void *userdata) {
@@ -1015,6 +1050,8 @@ static int help(int argc, char *argv[], void *userdata) {
" install Install systemd-boot to the ESP and EFI variables\n"
" update Update systemd-boot in the ESP and EFI variables\n"
" remove Remove systemd-boot from the ESP and EFI variables\n"
" random-seed Initialize random seed in ESP and EFI variables\n"
" is-installed Test whether systemd-boot is installed in the ESP\n"
"\nBoot Loader Entries Commands:\n"
" list List boot loader entries\n"
" set-default ID Set default boot loader entry\n"
@@ -1154,12 +1191,13 @@ static int verb_status(int argc, char *argv[], void *userdata) {
uint64_t flag;
const char *name;
} flags[] = {
{ EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
{ EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
{ EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
{ EFI_LOADER_FEATURE_BOOT_COUNTING, "Boot counting" },
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT, "Menu timeout control" },
{ EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT, "One-shot menu timeout control" },
{ EFI_LOADER_FEATURE_ENTRY_DEFAULT, "Default entry control" },
{ EFI_LOADER_FEATURE_ENTRY_ONESHOT, "One-shot entry control" },
{ EFI_LOADER_FEATURE_XBOOTLDR, "Support for XBOOTLDR partition" },
{ EFI_LOADER_FEATURE_RANDOM_SEED, "Support for passing random seed to OS" },
};
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL;
@@ -1212,6 +1250,22 @@ static int verb_status(int argc, char *argv[], void *userdata) {
printf(" ESP: n/a\n");
printf(" File: %s%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), strna(loader_path));
printf("\n");
printf("Random Seed:\n");
printf(" Passed to OS: %s\n", yes_no(access("/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f", F_OK) >= 0));
printf(" System Token: %s\n", access("/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f", F_OK) >= 0 ? "set" : "not set");
if (arg_esp_path) {
_cleanup_free_ char *p = NULL;
p = path_join(arg_esp_path, "/loader/random-seed");
if (!p)
return log_oom();
printf(" Exists: %s\n", yes_no(access(p, F_OK) >= 0));
}
printf("\n");
} else
printf("System:\n Not booted with EFI\n\n");
@@ -1284,6 +1338,122 @@ static int verb_list(int argc, char *argv[], void *userdata) {
return 0;
}
static int install_random_seed(const char *esp) {
_cleanup_(unlink_and_freep) char *tmp = NULL;
_cleanup_free_ void *buffer = NULL;
_cleanup_free_ char *path = NULL;
_cleanup_close_ int fd = -1;
size_t sz, token_size;
ssize_t n;
int r;
assert(esp);
path = path_join(esp, "/loader/random-seed");
if (!path)
return log_oom();
sz = random_pool_size();
buffer = malloc(sz);
if (!buffer)
return log_oom();
r = genuine_random_bytes(buffer, sz, RANDOM_BLOCK);
if (r < 0)
return log_error_errno(r, "Faile to acquire random seed: %m");
r = tempfn_random(path, "bootctl", &tmp);
if (r < 0)
return log_oom();
fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
if (fd < 0) {
tmp = mfree(tmp);
return log_error_errno(fd, "Failed to open random seed file for writing: %m");
}
n = write(fd, buffer, sz);
if (n < 0)
return log_error_errno(errno, "Failed to write random seed file: %m");
if ((size_t) n != sz)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
if (rename(tmp, path) < 0)
return log_error_errno(r, "Failed to move random seed file into place: %m");
tmp = mfree(tmp);
log_info("Successfully written random seed file %s with %zu bytes.", path, sz);
if (!arg_touch_variables)
return 0;
if (!is_efi_boot()) {
log_notice("Not booted with EFI, skipping EFI variable setup.");
return 0;
}
r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
if (r < 0) {
if (r != -ENXIO)
log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
if (detect_vm() > 0) {
/* Let's not write a system token if we detect we are running in a VM
* environment. Why? Our default security model for the random seed uses the system
* token as a mechanism to ensure we are not vulnerable to golden master sloppiness
* issues, i.e. that people initialize the random seed file, then copy the image to
* many systems and end up with the same random seed in each that is assumed to be
* valid but in reality is the same for all machines. By storing a system token in
* the EFI variable space we can make sure that even though the random seeds on disk
* are all the same they will be different on each system under the assumption that
* the EFI variable space is maintained separate from the random seed storage. That
* is generally the case on physical systems, as the ESP is stored on persistant
* storage, and the EFI variables in NVRAM. However in virtualized environments this
* is generally not true: the EFI variable set is typically stored along with the
* disk image itself. For example, using the OVMF EFI firmware the EFI variables are
* stored in a file in the ESP itself. */
log_notice("Not installing system token, since we are running in a virtualized environment.");
return 0;
}
} else if (r == 0) {
log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
return 0;
}
r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderSystemToken", NULL, NULL, &token_size);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to test system token validity: %m");
} else {
if (token_size >= sz) {
/* Let's avoid writes if we can, and initialize this only once. */
log_debug("System token already written, not updating.");
return 0;
}
log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sz);
}
r = genuine_random_bytes(buffer, sz, RANDOM_BLOCK);
if (r < 0)
return log_error_errno(r, "Failed to acquire random seed: %m");
/* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
* and possibly get identification information or too much insight into the kernel's entropy pool
* state. */
RUN_WITH_UMASK(0077) {
r = efi_set_variable(EFI_VENDOR_LOADER, "LoaderSystemToken", buffer, sz);
if (r < 0)
return log_error_errno(r, "Failed to set LoaderSystemToken EFI variable: %m");
}
log_info("Successfully initialized system token in EFI variable with %zu bytes.", sz);
return 0;
}
static int sync_everything(void) {
int ret = 0, k;
@@ -1329,7 +1499,11 @@ static int verb_install(int argc, char *argv[], void *userdata) {
/* Don't create any of these directories when we are just updating. When we update
* we'll drop-in our files (unless there are newer ones already), but we won't create
* the directories for them in the first place. */
r = create_esp_subdirs(arg_esp_path);
r = create_subdirs(arg_esp_path, esp_subdirs);
if (r < 0)
return r;
r = create_subdirs(arg_dollar_boot_path(), dollar_boot_subdirs);
if (r < 0)
return r;
}
@@ -1343,7 +1517,11 @@ static int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
r = install_entries_directories(arg_dollar_boot_path(), machine_id);
r = install_machine_id_directory(arg_dollar_boot_path(), machine_id);
if (r < 0)
return r;
r = install_random_seed(arg_esp_path);
if (r < 0)
return r;
}
@@ -1361,7 +1539,7 @@ static int verb_install(int argc, char *argv[], void *userdata) {
}
static int verb_remove(int argc, char *argv[], void *userdata) {
sd_id128_t uuid = SD_ID128_NULL;
sd_id128_t uuid = SD_ID128_NULL, machine_id;
int r, q;
r = acquire_esp(false, NULL, NULL, NULL, &uuid);
@@ -1372,31 +1550,97 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
r = sd_id128_get_machine(&machine_id);
if (r < 0)
return log_error_errno(r, "Failed to get machine id: %m");
r = remove_binaries(arg_esp_path);
q = remove_loader_config(arg_esp_path);
q = remove_file(arg_esp_path, "/loader/loader.conf");
if (q < 0 && r >= 0)
r = q;
q = remove_entries_directory(arg_dollar_boot_path());
q = remove_file(arg_esp_path, "/loader/random-seed");
if (q < 0 && r >= 0)
r = q;
q = remove_esp_subdirs(arg_esp_path);
q = remove_subdirs(arg_esp_path, esp_subdirs);
if (q < 0 && r >= 0)
r = q;
(void) sync_everything();
q = remove_subdirs(arg_esp_path, dollar_boot_subdirs);
if (q < 0 && r >= 0)
r = q;
if (arg_touch_variables) {
q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
q = remove_machine_id_directory(arg_esp_path, machine_id);
if (q < 0 && r >= 0)
r = 1;
if (arg_xbootldr_path) {
/* Remove the latter two also in the XBOOTLDR partition if it exists */
q = remove_subdirs(arg_xbootldr_path, dollar_boot_subdirs);
if (q < 0 && r >= 0)
r = q;
q = remove_machine_id_directory(arg_xbootldr_path, machine_id);
if (q < 0 && r >= 0)
r = q;
}
(void) sync_everything();
if (!arg_touch_variables)
return r;
q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
if (q < 0 && r >= 0)
r = q;
q = remove_loader_variables();
if (q < 0 && r >= 0)
r = q;
return r;
}
static int verb_is_installed(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *p = NULL;
int r;
r = acquire_esp(false, NULL, NULL, NULL, NULL);
if (r < 0)
return r;
/* Tests whether systemd-boot is installed. It's not obvious what to use as check here: we could
* check EFI variables, we could check what binary /EFI/BOOT/BOOT*.EFI points to, or whether the
* loader entries directory exists. Here we opted to check whether /EFI/systemd/ is non-empty, which
* should be a suitable and very minimal check for a number of reasons:
*
* → The check is architecture independent (i.e. we check if any systemd-boot loader is installed, not a
* specific one.)
*
* → It doesn't assume we are the only boot loader (i.e doesn't check if we own the main
* /EFI/BOOT/BOOT*.EFI fallback binary.
*
* → It specifically checks for systemd-boot, not for other boot loaders (which a check for
* /boot/loader/entries would do). */
p = path_join(arg_esp_path, "/EFI/systemd/");
if (!p)
return log_oom();
r = dir_is_empty(p);
if (r > 0 || r == -ENOENT) {
puts("no");
return EXIT_FAILURE;
}
if (r < 0)
return log_error_errno(r, "Failed to detect whether systemd-boot is installed: %m");
puts("yes");
return EXIT_SUCCESS;
}
static int verb_set_default(int argc, char *argv[], void *userdata) {
const char *name;
int r;
@@ -1445,16 +1689,33 @@ static int verb_set_default(int argc, char *argv[], void *userdata) {
return 0;
}
static int verb_random_seed(int argc, char *argv[], void *userdata) {
int r;
r = acquire_esp(false, NULL, NULL, NULL, NULL);
if (r < 0)
return r;
r = install_random_seed(arg_esp_path);
if (r < 0)
return r;
(void) sync_everything();
return 0;
}
static int bootctl_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, help },
{ "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
{ "install", VERB_ANY, 1, 0, verb_install },
{ "update", VERB_ANY, 1, 0, verb_install },
{ "remove", VERB_ANY, 1, 0, verb_remove },
{ "list", VERB_ANY, 1, 0, verb_list },
{ "set-default", 2, 2, 0, verb_set_default },
{ "set-oneshot", 2, 2, 0, verb_set_default },
{ "help", VERB_ANY, VERB_ANY, 0, help },
{ "status", VERB_ANY, 1, VERB_DEFAULT, verb_status },
{ "install", VERB_ANY, 1, 0, verb_install },
{ "update", VERB_ANY, 1, 0, verb_install },
{ "remove", VERB_ANY, 1, 0, verb_remove },
{ "random-seed", VERB_ANY, 1, 0, verb_random_seed },
{ "is-installed", VERB_ANY, 1, 0, verb_is_installed },
{ "list", VERB_ANY, 1, 0, verb_list },
{ "set-default", 2, 2, 0, verb_set_default },
{ "set-oneshot", 2, 2, 0, verb_set_default },
{}
};
+47 -2
View File
@@ -12,6 +12,7 @@
#include "loader-features.h"
#include "measure.h"
#include "pe.h"
#include "random-seed.h"
#include "shim.h"
#include "util.h"
@@ -68,6 +69,7 @@ typedef struct {
BOOLEAN force_menu;
UINTN console_mode;
enum console_mode_change_type console_mode_change;
RandomSeedMode random_seed_mode;
} Config;
static VOID cursor_left(UINTN *cursor, UINTN *first) {
@@ -396,6 +398,21 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) {
Print(L"editor: %s\n", yes_no(config->editor));
Print(L"auto-entries: %s\n", yes_no(config->auto_entries));
Print(L"auto-firmware: %s\n", yes_no(config->auto_firmware));
switch (config->random_seed_mode) {
case RANDOM_SEED_OFF:
Print(L"random-seed-mode: off\n");
break;
case RANDOM_SEED_WITH_SYSTEM_TOKEN:
Print(L"random-seed-node: with-system-token\n");
break;
case RANDOM_SEED_ALWAYS:
Print(L"random-seed-node: always\n");
break;
default:
;
}
Print(L"\n");
Print(L"config entry count: %d\n", config->entry_count);
@@ -1038,7 +1055,9 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->editor = on;
continue;
}
if (strcmpa((CHAR8 *)"auto-entries", key) == 0) {
@@ -1046,7 +1065,9 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->auto_entries = on;
continue;
}
if (strcmpa((CHAR8 *)"auto-firmware", key) == 0) {
@@ -1054,7 +1075,9 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->auto_firmware = on;
continue;
}
if (strcmpa((CHAR8 *)"console-mode", key) == 0) {
@@ -1074,6 +1097,23 @@ static VOID config_defaults_load_from_file(Config *config, CHAR8 *content) {
continue;
}
if (strcmpa((CHAR8*) "random-seed-mode", key) == 0) {
if (strcmpa((CHAR8*) "off", value) == 0)
config->random_seed_mode = RANDOM_SEED_OFF;
else if (strcmpa((CHAR8*) "with-system-token", value) == 0)
config->random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN;
else if (strcmpa((CHAR8*) "always", value) == 0)
config->random_seed_mode = RANDOM_SEED_ALWAYS;
else {
BOOLEAN on;
if (EFI_ERROR(parse_boolean(value, &on)))
continue;
config->random_seed_mode = on ? RANDOM_SEED_ALWAYS : RANDOM_SEED_OFF;
}
}
}
}
@@ -1404,6 +1444,7 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) {
.editor = TRUE,
.auto_entries = TRUE,
.auto_firmware = TRUE,
.random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN,
};
err = file_read(root_dir, L"\\loader\\loader.conf", 0, 0, &content, NULL);
@@ -2284,6 +2325,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
EFI_LOADER_FEATURE_ENTRY_ONESHOT |
EFI_LOADER_FEATURE_BOOT_COUNTING |
EFI_LOADER_FEATURE_XBOOTLDR |
EFI_LOADER_FEATURE_RANDOM_SEED |
0;
_cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL;
@@ -2435,8 +2477,11 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
config_entry_bump_counters(entry, root_dir);
/* export the selected boot entry to the system */
efivar_set(L"LoaderEntrySelected", entry->id, FALSE);
/* Export the selected boot entry to the system */
(VOID) efivar_set(L"LoaderEntrySelected", entry->id, FALSE);
/* Optionally, read a random seed off the ESP and pass it to the OS */
(VOID) process_random_seed(root_dir, config.random_seed_mode);
uefi_call_wrapper(BS->SetWatchdogTimer, 4, 5 * 60, 0x10000, 0, NULL);
err = image_start(image, &config, entry);
+1
View File
@@ -11,3 +11,4 @@
#define EFI_LOADER_FEATURE_ENTRY_ONESHOT (UINT64_C(1) << 3)
#define EFI_LOADER_FEATURE_BOOT_COUNTING (UINT64_C(1) << 4)
#define EFI_LOADER_FEATURE_XBOOTLDR (UINT64_C(1) << 5)
#define EFI_LOADER_FEATURE_RANDOM_SEED (UINT64_C(1) << 6)
+5 -1
View File
@@ -8,6 +8,8 @@ efi_headers = files('''
linux.h
measure.h
pe.h
random-seed.h
sha256.h
shim.h
splash.h
util.h
@@ -24,8 +26,10 @@ common_sources = '''
systemd_boot_sources = '''
boot.c
console.c
shim.c
crc32.c
random-seed.c
sha256.c
shim.c
'''.split()
stub_sources = '''
+340
View File
@@ -0,0 +1,340 @@
#include <efi.h>
#include <efilib.h>
#include "random-seed.h"
#include "sha256.h"
#include "util.h"
#include "shim.h"
#define RANDOM_MAX_SIZE_MIN (32U)
#define RANDOM_MAX_SIZE_MAX (32U*1024U)
static const EFI_GUID rng_protocol_guid = EFI_RNG_PROTOCOL_GUID;
/* SHA256 gives us 256/8=32 bytes */
#define HASH_VALUE_SIZE 32
static EFI_STATUS acquire_rng(UINTN size, VOID **ret) {
_cleanup_freepool_ VOID *data = NULL;
EFI_RNG_PROTOCOL *rng;
EFI_STATUS err;
/* Try to acquire the specified number of bytes from the UEFI RNG */
err = LibLocateProtocol((EFI_GUID*) &rng_protocol_guid, (VOID**) &rng);
if (EFI_ERROR(err)) {
Print(L"Failed to acquire RNG protocol: %r\n", err);
return err;
}
if (!rng) {
/* Print(L"RNG protocol not available.\n"); */
return EFI_UNSUPPORTED;
}
data = AllocatePool(size);
if (!data)
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;
}
*ret = TAKE_PTR(data);
return EFI_SUCCESS;
}
static VOID hash_once(
const VOID *old_seed,
const VOID *rng,
UINTN size,
const VOID *system_token,
UINTN system_token_size,
UINTN counter,
UINT8 ret[static HASH_VALUE_SIZE]) {
/* This hashes together:
*
* 1. The contents of the old seed file
* 2. Some random data acquired from the UEFI RNG (optional)
* 3. Some 'system token' the installer installed as EFI variable (optional)
* 4. A counter value
*
* And writes the result to the specified buffer.
*/
struct sha256_ctx hash;
sha256_init_ctx(&hash);
sha256_process_bytes(old_seed, size, &hash);
if (rng)
sha256_process_bytes(rng, size, &hash);
if (system_token_size > 0)
sha256_process_bytes(system_token, system_token_size, &hash);
sha256_process_bytes(&counter, sizeof(counter), &hash);
sha256_finish_ctx(&hash, ret);
}
static EFI_STATUS hash_many(
const VOID *old_seed,
const VOID *rng,
UINTN size,
const VOID *system_token,
UINTN system_token_size,
UINTN counter_start,
UINTN n,
VOID **ret) {
_cleanup_freepool_ VOID *output = NULL;
UINTN i;
/* Hashes the specified parameters in counter mode, generating n hash values, with the counter in the
* range counter_start…counter_start+n-1. */
output = AllocatePool(n * HASH_VALUE_SIZE);
if (!output)
return log_oom();
for (i = 0; i < n; i++)
hash_once(old_seed, rng, size,
system_token, system_token_size,
counter_start + i,
(UINT8*) output + (i * HASH_VALUE_SIZE));
*ret = TAKE_PTR(output);
return EFI_SUCCESS;
}
static EFI_STATUS mangle_random_seed(
const VOID *old_seed,
const VOID *rng,
UINTN size,
const VOID *system_token,
UINTN system_token_size,
VOID **ret_new_seed,
VOID **ret_for_kernel) {
_cleanup_freepool_ VOID *new_seed = NULL, *for_kernel = NULL;
EFI_STATUS err;
UINTN n;
/* 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
* kernel. To keep things simple, the new seed and kernel data have the same size as the old seed and
* RNG data. */
n = (size + HASH_VALUE_SIZE - 1) / HASH_VALUE_SIZE;
/* Begin hashing in counter mode at counter 0 for the new seed for the disk */
err = hash_many(old_seed, rng, size, system_token, system_token_size, 0, n, &new_seed);
if (EFI_ERROR(err))
return err;
/* Continue counting at 'n' for the seed for the kernel */
err = hash_many(old_seed, rng, size, system_token, system_token_size, n, n, &for_kernel);
if (EFI_ERROR(err))
return err;
*ret_new_seed = TAKE_PTR(new_seed);
*ret_for_kernel = TAKE_PTR(for_kernel);
return EFI_SUCCESS;
}
EFI_STATUS acquire_system_token(VOID **ret, UINTN *ret_size) {
_cleanup_freepool_ CHAR8 *data = NULL;
EFI_STATUS err;
UINTN 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);
return err;
}
if (size <= 0) {
Print(L"System token too short, ignoring.");
return EFI_NOT_FOUND;
}
*ret = TAKE_PTR(data);
*ret_size = size;
return EFI_SUCCESS;
}
static VOID validate_sha256(void) {
#ifndef __OPTIMIZE__
/* 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. */
static const struct {
const char *string;
uint8_t hash[HASH_VALUE_SIZE];
} array[] = {
{ "abc",
{ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }},
{ "",
{ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }},
{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
{ 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }},
{ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
{ 0xcf, 0x5b, 0x16, 0xa7, 0x78, 0xaf, 0x83, 0x80,
0x03, 0x6c, 0xe5, 0x9e, 0x7b, 0x04, 0x92, 0x37,
0x0b, 0x24, 0x9b, 0x11, 0xe8, 0xf0, 0x7a, 0x51,
0xaf, 0xac, 0x45, 0x03, 0x7a, 0xfe, 0xe9, 0xd1 }},
};
UINTN i;
for (i = 0; i < ELEMENTSOF(array); i++) {
struct sha256_ctx hash;
uint8_t result[HASH_VALUE_SIZE];
sha256_init_ctx(&hash);
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;
}
}
Print(L"SHA256 validated\n");
#endif
}
EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) {
_cleanup_freepool_ VOID *seed = NULL, *new_seed = NULL, *rng = NULL, *for_kernel = NULL, *system_token = NULL;
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
UINTN size, rsize, wsize, system_token_size = 0;
_cleanup_freepool_ EFI_FILE_INFO *info = NULL;
EFI_STATUS err;
validate_sha256();
if (mode == RANDOM_SEED_OFF) {
/* Print(L"Random seed handling turned off.\n"); */
return EFI_NOT_FOUND;
}
/* Let's better be safe than sorry, and for now disable this logic in SecureBoot mode, so that we
* don't credit a random seed that is not authenticated. */
if (secure_boot_enabled()) {
/* Print(L"Not loading random seed, because we are in SecureBoot mode.\n"); */
return EFI_NOT_FOUND;
}
/* Get some system specific seed that the installer might have placed in an EFI variable. We include
* it in our hash. This is protection against golden master image sloppiness, and it remains on the
* system, even when disk images are duplicated or swapped out. */
err = acquire_system_token(&system_token, &system_token_size);
if (mode != RANDOM_SEED_ALWAYS) {
/* if (err == EFI_NOT_FOUND) */
/* Print(L"Not loading random seed, because no system token is set.\n"); */
if (EFI_ERROR(err))
return err; /* in all other error cases we already logged */
}
err = uefi_call_wrapper(root_dir->Open, 5, root_dir, &handle, L"\\loader\\random-seed", EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0ULL);
if (EFI_ERROR(err)) {
if (err != EFI_NOT_FOUND)
Print(L"Failed to open random seed file: %r\n", err);
/* else */
/* Print(L"Not loading random seed, because there is none.\n"); */
return err;
}
info = LibFileInfo(handle);
if (!info)
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_MAX) {
Print(L"Random seed file is too large?\n");
return EFI_INVALID_PARAMETER;
}
seed = AllocatePool(size);
if (!seed)
return log_oom();
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;
}
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;
}
/* 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
* golden master images that are replicated many times. */
(VOID) acquire_rng(size, &rng); /* It's fine if this fails */
/* Calculate new random seed for the disk and what to pass to the kernel */
err = mangle_random_seed(seed, rng, size, system_token, system_token_size, &new_seed, &for_kernel);
if (EFI_ERROR(err))
return err;
/* 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;
}
err = uefi_call_wrapper(handle->Flush, 1, handle);
if (EFI_ERROR(err)) {
Print(L"Failed to flush random seed file: %r\n");
return err;
}
/* We are good to go */
err = efivar_set_raw(&loader_guid, L"LoaderRandomSeed", for_kernel, size, FALSE);
if (EFI_ERROR(err)) {
Print(L"Failed to write random seed to EFI variable: %r\n", err);
return err;
}
return EFI_SUCCESS;
}
+14
View File
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <efi.h>
typedef enum RandomSeedMode {
RANDOM_SEED_OFF,
RANDOM_SEED_WITH_SYSTEM_TOKEN,
RANDOM_SEED_ALWAYS,
_RANDOM_SEED_MODE_MAX,
_RANDOM_SEED_MODE_INVALID = -1,
} RandomSeedMode;
EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode);
+275
View File
@@ -0,0 +1,275 @@
/* Stolen from glibc and converted to UEFI style. In glibc it comes with the following copyright blurb: */
/* Functions to compute SHA256 message digest of files or memory blocks.
according to the definition of SHA256 in FIPS 180-2.
Copyright (C) 2007-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
/* Written by Ulrich Drepper <drepper@redhat.com>, 2007. */
#include "sha256.h"
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
# define SWAP64(n) \
(((n) << 56) \
| (((n) & 0xff00) << 40) \
| (((n) & 0xff0000) << 24) \
| (((n) & 0xff000000) << 8) \
| (((n) >> 8) & 0xff000000) \
| (((n) >> 24) & 0xff0000) \
| (((n) >> 40) & 0xff00) \
| ((n) >> 56))
#else
# define SWAP(n) (n)
# define SWAP64(n) (n)
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (FIPS 180-2:5.1.1) */
static const UINT8 fillbuf[64] = {
0x80, 0 /* , 0, 0, ... */
};
/* Constants for SHA256 from FIPS 180-2:4.2.2. */
static const UINT32 K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
};
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) {
ctx->H[0] = 0x6a09e667;
ctx->H[1] = 0xbb67ae85;
ctx->H[2] = 0x3c6ef372;
ctx->H[3] = 0xa54ff53a;
ctx->H[4] = 0x510e527f;
ctx->H[5] = 0x9b05688c;
ctx->H[6] = 0x1f83d9ab;
ctx->H[7] = 0x5be0cd19;
ctx->total64 = 0;
ctx->buflen = 0;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) {
/* Take yet unprocessed bytes into account. */
UINT32 bytes = ctx->buflen;
UINTN pad, i;
/* Now count remaining bytes. */
ctx->total64 += bytes;
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
CopyMem (&ctx->buffer[bytes], fillbuf, pad);
/* Put the 64-bit file length in *bits* at the end of the buffer. */
ctx->buffer32[(bytes + pad + 4) / 4] = SWAP (ctx->total[TOTAL64_low] << 3);
ctx->buffer32[(bytes + pad) / 4] = SWAP ((ctx->total[TOTAL64_high] << 3)
| (ctx->total[TOTAL64_low] >> 29));
/* Process last bytes. */
sha256_process_block (ctx->buffer, bytes + pad + 8, ctx);
/* Put result from CTX in first 32 bytes following RESBUF. */
for (i = 0; i < 8; ++i)
((UINT32 *) resbuf)[i] = SWAP (ctx->H[i]);
return resbuf;
}
void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx) {
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0) {
UINTN left_over = ctx->buflen;
UINTN add = 128 - left_over > len ? len : 128 - left_over;
CopyMem (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 64) {
sha256_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
ctx->buflen &= 63;
/* The regions in the following copy operation cannot overlap. */
CopyMem (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 64) {
#if !_STRING_ARCH_unaligned
/* To check alignment gcc has an appropriate operator. Other
compilers don't. */
# if __GNUC__ >= 2
# define UNALIGNED_P(p) (((UINTN) p) % __alignof__ (UINT32) != 0)
# else
# define UNALIGNED_P(p) (((UINTN) p) % sizeof (UINT32) != 0)
# endif
if (UNALIGNED_P (buffer))
while (len > 64) {
CopyMem (ctx->buffer, buffer, 64);
sha256_process_block (ctx->buffer, 64, ctx);
buffer = (const char *) buffer + 64;
len -= 64;
}
else
#endif
{
sha256_process_block (buffer, len & ~63, ctx);
buffer = (const char *) buffer + (len & ~63);
len &= 63;
}
}
/* Move remaining bytes into internal buffer. */
if (len > 0) {
UINTN left_over = ctx->buflen;
CopyMem (&ctx->buffer[left_over], buffer, len);
left_over += len;
if (left_over >= 64) {
sha256_process_block (ctx->buffer, 64, ctx);
left_over -= 64;
CopyMem (ctx->buffer, &ctx->buffer[64], left_over);
}
ctx->buflen = left_over;
}
}
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 64 == 0. */
static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ctx *ctx) {
const UINT32 *words = buffer;
UINTN nwords = len / sizeof (UINT32);
UINT32 a = ctx->H[0];
UINT32 b = ctx->H[1];
UINT32 c = ctx->H[2];
UINT32 d = ctx->H[3];
UINT32 e = ctx->H[4];
UINT32 f = ctx->H[5];
UINT32 g = ctx->H[6];
UINT32 h = ctx->H[7];
/* First increment the byte count. FIPS 180-2 specifies the possible
length of the file up to 2^64 bits. Here we only compute the
number of bytes. */
ctx->total64 += len;
/* Process all bytes in the buffer with 64 bytes in each round of
the loop. */
while (nwords > 0) {
UINT32 W[64];
UINT32 a_save = a;
UINT32 b_save = b;
UINT32 c_save = c;
UINT32 d_save = d;
UINT32 e_save = e;
UINT32 f_save = f;
UINT32 g_save = g;
UINT32 h_save = h;
UINTN t;
/* Operators defined in FIPS 180-2:4.1.2. */
#define Ch(x, y, z) ((x & y) ^ (~x & z))
#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
/* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
for (t = 0; t < 16; ++t) {
W[t] = SWAP (*words);
++words;
}
for (t = 16; t < 64; ++t)
W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
/* The actual computation according to FIPS 180-2:6.2.2 step 3. */
for (t = 0; t < 64; ++t) {
UINT32 T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
UINT32 T2 = S0 (a) + Maj (a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
/* Add the starting values of the context according to FIPS 180-2:6.2.2
step 4. */
a += a_save;
b += b_save;
c += c_save;
d += d_save;
e += e_save;
f += f_save;
g += g_save;
h += h_save;
/* Prepare for the next round. */
nwords -= 16;
}
/* Put checksum in context given as argument. */
ctx->H[0] = a;
ctx->H[1] = b;
ctx->H[2] = c;
ctx->H[3] = d;
ctx->H[4] = e;
ctx->H[5] = f;
ctx->H[6] = g;
ctx->H[7] = h;
}
+28
View File
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <efi.h>
#include <efilib.h>
struct sha256_ctx {
UINT32 H[8];
union {
UINT64 total64;
#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
UINT32 total[2];
};
UINT32 buflen;
union {
UINT8 buffer[128]; /* NB: always correctly aligned for UINT32. */
UINT32 buffer32[32];
UINT64 buffer64[16];
};
};
void sha256_init_ctx(struct sha256_ctx *ctx);
void *sha256_finish_ctx(struct sha256_ctx *ctx, VOID *resbuf);
void sha256_process_bytes(const void *buffer, UINTN len, struct sha256_ctx *ctx);
+22 -10
View File
@@ -309,8 +309,8 @@ CHAR8 *strchra(CHAR8 *s, CHAR8 c) {
return NULL;
}
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **content, UINTN *content_size) {
EFI_FILE_HANDLE handle;
EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN size, CHAR8 **ret, UINTN *ret_size) {
_cleanup_(FileHandleClosep) EFI_FILE_HANDLE handle = NULL;
_cleanup_freepool_ CHAR8 *buf = NULL;
EFI_STATUS err;
@@ -322,6 +322,9 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
_cleanup_freepool_ EFI_FILE_INFO *info;
info = LibFileInfo(handle);
if (!info)
return EFI_OUT_OF_RESOURCES;
size = info->FileSize+1;
}
@@ -332,15 +335,24 @@ EFI_STATUS file_read(EFI_FILE_HANDLE dir, const CHAR16 *name, UINTN off, UINTN s
}
buf = AllocatePool(size + 1);
if (!buf)
return EFI_OUT_OF_RESOURCES;
err = uefi_call_wrapper(handle->Read, 3, handle, &size, buf);
if (!EFI_ERROR(err)) {
buf[size] = '\0';
*content = buf;
buf = NULL;
if (content_size)
*content_size = size;
}
uefi_call_wrapper(handle->Close, 1, handle);
if (EFI_ERROR(err))
return err;
buf[size] = '\0';
*ret = TAKE_PTR(buf);
if (ret_size)
*ret_size = size;
return err;
}
EFI_STATUS log_oom(void) {
Print(L"Out of memory.");
(void) uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
return EFI_OUT_OF_RESOURCES;
}
+2
View File
@@ -66,3 +66,5 @@ const EFI_GUID loader_guid;
(ptr) = NULL; \
_ptr_; \
})
EFI_STATUS log_oom(void);