Merge pull request #25319 from zx2c4-forks/krngseed

boot: implement kernel EFI RNG seed protocol with proper hashing
This commit is contained in:
Luca Boccassi
2022-11-16 15:07:54 +01:00
committed by GitHub
14 changed files with 352 additions and 301 deletions
+13 -69
View File
@@ -12,79 +12,23 @@
#include "random-util.h"
#include "strv.h"
/* If a random seed was passed by the boot loader in the LoaderRandomSeed EFI variable, let's credit it to
* the kernel's random pool, but only once per boot. If this is run very early during initialization we can
* instantly boot up with a filled random pool.
*
* This makes no judgement on the entropy passed, it's the job of the boot loader to only pass us a seed that
* is suitably validated. */
static void lock_down_efi_variables(void) {
void lock_down_efi_variables(void) {
_cleanup_close_ int fd = -1;
int r;
fd = open(EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken)), O_RDONLY|O_CLOEXEC);
if (fd < 0) {
if (errno != ENOENT)
log_warning_errno(errno, "Unable to open LoaderSystemToken EFI variable, ignoring: %m");
return;
}
/* Paranoia: let's restrict access modes of these a bit, so that unprivileged users can't use them to
* identify the system or gain too much insight into what we might have credited to the entropy
* pool. */
FOREACH_STRING(path,
EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderRandomSeed)),
EFIVAR_PATH(EFI_LOADER_VARIABLE(LoaderSystemToken))) {
r = chattr_path(path, 0, FS_IMMUTABLE_FL, NULL);
if (r == -ENOENT)
continue;
if (r < 0)
log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", path);
if (chmod(path, 0600) < 0)
log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", path);
}
}
int efi_take_random_seed(void) {
_cleanup_free_ void *value = NULL;
size_t size;
int r;
/* Paranoia comes first. */
lock_down_efi_variables();
if (access("/run/systemd/efi-random-seed-taken", F_OK) < 0) {
if (errno != ENOENT) {
log_warning_errno(errno, "Failed to determine whether we already used the random seed token, not using it.");
return 0;
}
/* ENOENT means we haven't used it yet. */
} else {
log_debug("EFI random seed already used, not using again.");
return 0;
}
r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderRandomSeed), NULL, &value, &size);
if (r == -EOPNOTSUPP) {
log_debug_errno(r, "System lacks EFI support, not initializing random seed from EFI variable.");
return 0;
}
if (r == -ENOENT) {
log_debug_errno(r, "Boot loader did not pass LoaderRandomSeed EFI variable, not crediting any entropy.");
return 0;
}
r = chattr_fd(fd, 0, FS_IMMUTABLE_FL, NULL);
if (r < 0)
return log_warning_errno(r, "Failed to read LoaderRandomSeed EFI variable, ignoring: %m");
if (size == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring.");
/* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice
* way to let users known that we successfully acquired entropy from the boot loader. */
r = touch("/run/systemd/efi-random-seed-taken");
if (r < 0)
return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m");
r = random_write_entropy(-1, value, size, true);
if (r < 0)
return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m");
log_info("Successfully credited entropy passed from boot loader.");
return 1;
log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from LoaderSystemToken EFI variable, ignoring: %m");
if (fchmod(fd, 0600) < 0)
log_warning_errno(errno, "Failed to reduce access mode of LoaderSystemToken EFI variable, ignoring: %m");
}
+1 -1
View File
@@ -1,4 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
int efi_take_random_seed(void);
void lock_down_efi_variables(void);
+2 -2
View File
@@ -2831,8 +2831,8 @@ int main(int argc, char *argv[]) {
goto finish;
}
/* The efivarfs is now mounted, let's read the random seed off it */
(void) efi_take_random_seed();
/* The efivarfs is now mounted, let's lock down the system token. */
lock_down_efi_variables();
/* Cache command-line options passed from EFI variables */
if (!skip_setup)