1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-05 09:17:44 +03:00

Merge pull request #25802 from poettering/bootctl-reseed

move EFI random seed update logic from systemd-random-seed.service into separate service
This commit is contained in:
Lennart Poettering 2023-01-04 17:49:21 +01:00 committed by GitHub
commit e03fa62b63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 224 additions and 256 deletions

View File

@ -208,7 +208,7 @@
OS and a new seed to store in the ESP from the combination of both. The random seed passed to the OS
is credited to the kernel's entropy pool by the system manager during early boot, and permits
userspace to boot up with an entropy pool fully initialized very early on. Also see
<citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
<para>See <ulink url="https://systemd.io/RANDOM_SEEDS">Random Seeds</ulink> for further
information.</para></listitem>
@ -531,7 +531,7 @@ Boot Loader Entries:
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>,
<ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>,
<citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
<citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -864,7 +864,7 @@ manpages = [
'8',
['systemd-boot-check-no-failures'],
''],
['systemd-boot-system-token.service', '8', [], 'HAVE_GNU_EFI'],
['systemd-boot-random-seed.service', '8', [], 'HAVE_GNU_EFI'],
['systemd-boot', '7', ['sd-boot'], 'HAVE_GNU_EFI'],
['systemd-cat', '1', [], ''],
['systemd-cgls', '1', [], ''],

View File

@ -0,0 +1,99 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-boot-random-seed.service" conditional='HAVE_GNU_EFI'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-boot-random-seed.service</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-boot-random-seed.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-boot-random-seed.service</refname>
<refpurpose>Refresh boot loader random seed at boot</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-boot-random-seed.service</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><filename>systemd-boot-random-seed.service</filename> is a system service that automatically
refreshes the boot loader random seed stored in the EFI System Partition (ESP), from the Linux kernel
entropy pool. The boot loader random seed is primarily consumed and updated by
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> from the
UEFI environemnt (or
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry> if the
former is not used, but the latter is), and passed as initial RNG seed to the OS. It is an effective way
to ensure the OS comes up with a random pool that is fully initialized.</para>
<para>The service also automatically generates a 'system token' to store in an EFI variable in the
system's NVRAM. The boot loader may then combine the on-disk random seed and the system token by
cryptographic hashing, and pass it to the OS it boots as initialization seed for its entropy pool. Note:
the random seed stored in the ESP is refreshed on <emphasis>every</emphasis> reboot ensuring that
multiple subsequent boots will boot with different seeds. On the other hand, the system token is
generated randomly <emphasis>once</emphasis>, and then persistently stored in the system's EFI variable
storage, ensuring the same disk image won't result in the same series of boot loader seed values if used
on multiple systems in parallel.</para>
<para>The <filename>systemd-boot-random-seed.service</filename> unit invokes the <command>bootctl
random-seed</command> command, which updates the random seed in the ESP, and initializes the system
token if it's not initialized yet. The service is conditionalized so that it is run only when a boot
loader is used that implements the <ulink url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader
Interface</ulink>.</para> <para>For further details see
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, regarding
the command this service invokes.</para>
<para>Note the relationship between <filename>systemd-boot-random-seed.service</filename> and
<citerefentry><refentrytitle>systemd-random-seed</refentrytitle><manvolnum>8</manvolnum></citerefentry>. The
former maintains the random seed consumed and updated by the boot environment (i.e. by
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> or
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>), the
latter maintains a random seed consumed and updated by the OS itself. The former ensures that the OS has
a filled entropy pool already during earliest boot when regular disk access is not available yet
(i.e. when the OS random seed cannot be loaded yet). The latter is processed much later, once writable
disk access is available. Thus it cannot be used to seed the initial boot phase, but typically has much
higher quality of entropy. Both files are consumed and updated at boot, but at different
times. Specifically:</para>
<orderedlist>
<listitem><para>In UEFI mode, the <filename>systemd-boot</filename> or
<filename>systemd-stub</filename> components load the boot loader random seed off the ESP, hash it with
available entropy and the system token, and then update it on disk. A derived seed is passed to the
kernel which writes it to its entropy pool.</para></listitem>
<listitem><para>In userspace the <filename>systemd-random-seed.service</filename> service loads the OS
random seed, writes it to the kernel entropy pool, and then updates it on disk with a new value derived
from the kernel entropy pool.</para></listitem>
<listitem><para>In userspace the <filename>systemd-boot-random-seed.service</filename> service updates
the boot loader random seed with a new value derived from the kernel kernel entropy pool.</para></listitem>
</orderedlist>
<para>This logic should ensure that the kernel's entropy pool is seeded during earliest bool already, if
possible, but the highest quality entropy is propagated back to both on-disk seeds.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -1,76 +0,0 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-boot-system-token.service" conditional='HAVE_GNU_EFI'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-boot-system-token.service</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-boot-system-token.service</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-boot-system-token.service</refname>
<refpurpose>Generate an initial boot loader system token and random seed</refpurpose>
</refnamediv>
<refsynopsisdiv>
<para><filename>systemd-boot-system-token.service</filename></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><filename>systemd-boot-system-token.service</filename> is a system service that automatically
generates a 'system token' to store in an EFI variable in the system's NVRAM and a random seed to store
on the EFI System Partition ESP on disk. The boot loader may then combine these two randomized data
fields by cryptographic hashing, and pass it to the OS it boots as initialization seed for its entropy
pool. The random seed stored in the ESP is refreshed on each reboot ensuring that multiple subsequent
boots will boot with different seeds. The 'system token' is generated randomly once, and then
persistently stored in the system's EFI variable storage.</para>
<para>The <filename>systemd-boot-system-token.service</filename> unit invokes the <command>bootctl
random-seed</command> command, which updates the random seed in the ESP, and initializes the 'system
token' if it's not initialized yet. The service is conditionalized so that it is run only when all of the
below apply:</para>
<itemizedlist>
<listitem><para>A boot loader is used that implements the <ulink
url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink> (which defines the 'system
token' concept).</para></listitem>
<listitem><para>Either a 'system token' was not set yet, or the boot loader has not passed the OS a
random seed yet (and thus most likely has been missing the random seed file in the
ESP).</para></listitem>
<listitem><para>The system is not running in a VM environment. This case is explicitly excluded since
on VM environments the ESP backing storage and EFI variable storage is typically not physically
separated and hence booting the same OS image in multiple instances would replicate both, thus reusing
the same random seed and 'system token' among all instances, which defeats its purpose. Note that it's
still possible to use boot loader random seed provisioning in this mode, but the automatic logic
implemented by this service has no effect then, and the user instead has to manually invoke the
<command>bootctl random-seed</command> acknowledging these restrictions.</para></listitem>
</itemizedlist>
<para>For further details see
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, regarding
the command this service invokes.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -526,7 +526,7 @@
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-bless-boot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot-system-token.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification">Boot Loader Specification</ulink>,

View File

@ -18,7 +18,7 @@
<refnamediv>
<refname>systemd-random-seed.service</refname>
<refname>systemd-random-seed</refname>
<refpurpose>Load and save the system random seed at boot and shutdown</refpurpose>
<refpurpose>Load and save the OS system random seed at boot and shutdown</refpurpose>
</refnamediv>
<refsynopsisdiv>
@ -86,7 +86,9 @@
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>4</manvolnum></citerefentry>
<citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>4</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-boot-random-seed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>

View File

@ -9,61 +9,19 @@
#include "fd-util.h"
#include "find-esp.h"
#include "fs-util.h"
#include "io-util.h"
#include "mkdir.h"
#include "path-util.h"
#include "random-util.h"
#include "sha256.h"
#include "tmpfile-util.h"
#include "umask-util.h"
int install_random_seed(const char *esp) {
_cleanup_(unlink_and_freep) char *tmp = NULL;
static int set_system_token(void) {
uint8_t buffer[RANDOM_EFI_SEED_SIZE];
_cleanup_free_ char *path = NULL;
_cleanup_close_ int fd = -EBADF;
size_t token_size;
ssize_t n;
int r;
assert(esp);
path = path_join(esp, "/loader/random-seed");
if (!path)
return log_oom();
r = crypto_random_bytes(buffer, sizeof(buffer));
if (r < 0)
return log_error_errno(r, "Failed to acquire random seed: %m");
/* Normally create_subdirs() should already have created everything we need, but in case "bootctl
* random-seed" is called we want to just create the minimum we need for it, and not the full
* list. */
r = mkdir_parents(path, 0755);
if (r < 0)
return log_error_errno(r, "Failed to create parent directory for %s: %m", path);
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, sizeof(buffer));
if (n < 0)
return log_error_errno(errno, "Failed to write random seed file: %m");
if ((size_t) n != sizeof(buffer))
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("Random seed file %s successfully written (%zu bytes).", path, sizeof(buffer));
if (!arg_touch_variables)
return 0;
@ -117,9 +75,9 @@ int install_random_seed(const char *esp) {
return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
if (r == -EINVAL)
log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
else
log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
log_notice_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
} else
log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
}
@ -127,6 +85,96 @@ int install_random_seed(const char *esp) {
return 0;
}
int install_random_seed(const char *esp) {
_cleanup_close_ int esp_fd = -EBADF, loader_dir_fd = -EBADF, fd = -EBADF;
_cleanup_free_ char *tmp = NULL;
uint8_t buffer[RANDOM_EFI_SEED_SIZE];
struct sha256_ctx hash_state;
bool refreshed;
int r;
assert(esp);
assert_cc(RANDOM_EFI_SEED_SIZE == SHA256_DIGEST_SIZE);
esp_fd = open(esp, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
if (esp_fd < 0)
return log_error_errno(errno, "Failed to open ESP directory '%s': %m", esp);
loader_dir_fd = open_mkdir_at(esp_fd, "loader", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOFOLLOW, 0775);
if (loader_dir_fd < 0)
return log_error_errno(loader_dir_fd, "Failed to open loader directory '%s/loader': %m", esp);
r = crypto_random_bytes(buffer, sizeof(buffer));
if (r < 0)
return log_error_errno(r, "Failed to acquire random seed: %m");
sha256_init_ctx(&hash_state);
sha256_process_bytes_and_size(buffer, sizeof(buffer), &hash_state);
fd = openat(loader_dir_fd, "random-seed", O_NOFOLLOW|O_CLOEXEC|O_RDONLY|O_NOCTTY);
if (fd < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to open old random seed file: %m");
sha256_process_bytes(&(const ssize_t) { 0 }, sizeof(ssize_t), &hash_state);
refreshed = false;
} else {
ssize_t n;
/* Hash the old seed in so that we never regress in entropy. */
n = read(fd, buffer, sizeof(buffer));
if (n < 0)
return log_error_errno(errno, "Failed to read old random seed file: %m");
sha256_process_bytes_and_size(buffer, n, &hash_state);
fd = safe_close(fd);
refreshed = n > 0;
}
sha256_finish_ctx(&hash_state, buffer);
if (tempfn_random("random-seed", "bootctl", &tmp) < 0)
return log_oom();
fd = openat(loader_dir_fd, tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
if (fd < 0)
return log_error_errno(fd, "Failed to open random seed file for writing: %m");
r = loop_write(fd, buffer, sizeof(buffer), /* do_poll= */ false);
if (r < 0) {
log_error_errno(r, "Failed to write random seed file: %m");
goto fail;
}
if (fsync(fd) < 0 || fsync(loader_dir_fd) < 0) {
r = log_error_errno(errno, "Failed to sync random seed file: %m");
goto fail;
}
if (renameat(loader_dir_fd, tmp, loader_dir_fd, "random-seed") < 0) {
r = log_error_errno(errno, "Failed to move random seed file into place: %m");
goto fail;
}
tmp = mfree(tmp);
if (syncfs(fd) < 0)
return log_error_errno(errno, "Failed to sync ESP file system: %m");
log_info("Random seed file %s/loader/random-seed successfully %s (%zu bytes).", esp, refreshed ? "refreshed" : "written", sizeof(buffer));
return set_system_token();
fail:
if (tmp)
(void) unlinkat(loader_dir_fd, tmp, 0);
return r;
}
int verb_random_seed(int argc, char *argv[], void *userdata) {
int r;
@ -146,6 +194,5 @@ int verb_random_seed(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
(void) sync_everything();
return 0;
}

View File

@ -28,6 +28,11 @@ void sha256_init_ctx(struct sha256_ctx *ctx);
uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_DIGEST_SIZE]);
void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx);
static inline void sha256_process_bytes_and_size(const void *buffer, size_t len, struct sha256_ctx *ctx) {
sha256_process_bytes(&len, sizeof(len), ctx);
sha256_process_bytes(buffer, len, ctx);
}
uint8_t* sha256_direct(const void *buffer, size_t sz, uint8_t result[static SHA256_DIGEST_SIZE]);
#define SHA256_DIRECT(buffer, sz) sha256_direct(buffer, sz, (uint8_t[SHA256_DIGEST_SIZE]) {})

View File

@ -16,10 +16,7 @@
#include "alloc-util.h"
#include "build.h"
#include "chase-symlinks.h"
#include "efi-loader.h"
#include "fd-util.h"
#include "find-esp.h"
#include "fs-util.h"
#include "io-util.h"
#include "log.h"
@ -27,17 +24,13 @@
#include "missing_random.h"
#include "missing_syscall.h"
#include "mkdir.h"
#include "parse-argument.h"
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "random-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "sync-util.h"
#include "sha256.h"
#include "terminal-util.h"
#include "xattr-util.h"
typedef enum SeedAction {
@ -194,8 +187,7 @@ static int load_seed_file(
return log_oom();
sha256_init_ctx(hash_state);
sha256_process_bytes(&k, sizeof(k), hash_state); /* Hash length to distinguish from new seed. */
sha256_process_bytes(buf, k, hash_state);
sha256_process_bytes_and_size(buf, k, hash_state); /* Hash with length to distinguish from new seed. */
*ret_hash_state = hash_state;
}
@ -288,8 +280,7 @@ static int save_seed_file(
if (hash_state) {
uint8_t hash[SHA256_DIGEST_SIZE];
sha256_process_bytes(&k, sizeof(k), hash_state); /* Hash length to distinguish from old seed. */
sha256_process_bytes(buf, k, hash_state);
sha256_process_bytes_and_size(buf, k, hash_state); /* Hash with length to distinguish from old seed. */
sha256_finish_ctx(hash_state, hash);
l = MIN((size_t)k, sizeof(hash));
memcpy((uint8_t *)buf + k - l, hash, l);
@ -315,102 +306,6 @@ static int save_seed_file(
return 0;
}
static int refresh_boot_seed(void) {
uint8_t buffer[RANDOM_EFI_SEED_SIZE];
struct sha256_ctx hash_state;
_cleanup_free_ void *seed_file_bytes = NULL;
_cleanup_free_ char *esp_path = NULL;
_cleanup_close_ int seed_fd = -EBADF, dir_fd = -EBADF;
size_t len;
ssize_t n;
int r;
assert_cc(RANDOM_EFI_SEED_SIZE == SHA256_DIGEST_SIZE);
r = find_esp_and_warn(NULL, NULL, /* unprivileged_mode= */ false, &esp_path,
NULL, NULL, NULL, NULL, NULL);
if (r < 0) {
if (r == -ENOKEY) {
log_debug_errno(r, "Couldn't find any ESP, so not updating ESP random seed.");
return 0;
}
return r; /* find_esp_and_warn() already logged */
}
r = chase_symlinks("/loader", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, &dir_fd);
if (r < 0) {
if (r == -ENOENT) {
log_debug_errno(r, "Couldn't find ESP loader directory, so not updating ESP random seed.");
return 0;
}
return log_error_errno(r, "Failed to open ESP loader directory: %m");
}
seed_fd = openat(dir_fd, "random-seed", O_NOFOLLOW|O_RDWR|O_CLOEXEC|O_NOCTTY);
if (seed_fd < 0 && errno == ENOENT) {
uint64_t features;
r = efi_loader_get_features(&features);
if (r == 0 && FLAGS_SET(features, EFI_LOADER_FEATURE_RANDOM_SEED))
seed_fd = openat(dir_fd, "random-seed", O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY, 0600);
else {
log_debug_errno(seed_fd, "Couldn't find ESP random seed, and not booted with systemd-boot, so not updating ESP random seed.");
return 0;
}
}
if (seed_fd < 0)
return log_error_errno(errno, "Failed to open EFI seed path: %m");
r = random_seed_size(seed_fd, &len);
if (r < 0)
return log_error_errno(r, "Failed to determine EFI seed path length: %m");
seed_file_bytes = malloc(len);
if (!seed_file_bytes)
return log_oom();
n = loop_read(seed_fd, seed_file_bytes, len, false);
if (n < 0)
return log_error_errno(n, "Failed to read EFI seed file: %m");
/* Hash the old seed in so that we never regress in entropy. */
sha256_init_ctx(&hash_state);
sha256_process_bytes(&n, sizeof(n), &hash_state);
sha256_process_bytes(seed_file_bytes, n, &hash_state);
/* We're doing this opportunistically, so if the seeding dance before didn't manage to initialize the
* RNG, there's no point in doing it here. Secondly, getrandom(GRND_NONBLOCK) has been around longer
* than EFI seeding anyway, so there's no point in having non-getrandom() fallbacks here. So if this
* fails, just return early to cut our losses. */
n = getrandom(buffer, sizeof(buffer), GRND_NONBLOCK);
if (n < 0) {
if (errno == EAGAIN) {
log_debug_errno(errno, "Random pool not initialized yet, so skipping EFI seed update");
return 0;
}
if (errno == ENOSYS) {
log_debug_errno(errno, "getrandom() not available, so skipping EFI seed update");
return 0;
}
return log_error_errno(errno, "Failed to generate random bytes for EFI seed: %m");
}
assert(n == sizeof(buffer));
/* Hash the new seed into the state containing the old one to generate our final seed. */
sha256_process_bytes(&n, sizeof(n), &hash_state);
sha256_process_bytes(buffer, n, &hash_state);
sha256_finish_ctx(&hash_state, buffer);
if (lseek(seed_fd, 0, SEEK_SET) < 0)
return log_error_errno(errno, "Failed to seek to beginning of EFI seed file: %m");
r = loop_write(seed_fd, buffer, sizeof(buffer), false);
if (r < 0)
return log_error_errno(r, "Failed to write new EFI seed file: %m");
if (ftruncate(seed_fd, sizeof(buffer)) < 0)
return log_error_errno(errno, "Failed to truncate EFI seed file: %m");
r = fsync_full(seed_fd);
if (r < 0)
return log_error_errno(r, "Failed to fsync EFI seed file: %m");
log_debug("Updated random seed in ESP");
return 0;
}
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
@ -528,10 +423,7 @@ static int run(int argc, char *argv[]) {
log_full_errno(level, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m");
log_full_errno(level, errno, "Failed to open " RANDOM_SEED " for reading: %m");
r = -errno;
(void) refresh_boot_seed();
return missing ? 0 : r;
return missing ? 0 : -errno;
}
} else
write_seed_file = true;
@ -541,7 +433,6 @@ static int run(int argc, char *argv[]) {
break;
case ACTION_SAVE:
(void) refresh_boot_seed();
seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600);
if (seed_fd < 0)
return log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m");
@ -559,11 +450,9 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
if (read_seed_file) {
if (read_seed_file)
r = load_seed_file(seed_fd, random_fd, seed_size,
write_seed_file ? &hash_state : NULL);
(void) refresh_boot_seed();
}
if (r >= 0 && write_seed_file)
r = save_seed_file(seed_fd, random_fd, seed_size, synchronous, hash_state);

View File

@ -105,7 +105,7 @@ units = [
['systemd-ask-password-wall.path', '',
'multi-user.target.wants/'],
['systemd-ask-password-wall.service', ''],
['systemd-boot-system-token.service', 'HAVE_GNU_EFI',
['systemd-boot-random-seed.service', 'HAVE_GNU_EFI',
'sysinit.target.wants/'],
['systemd-boot-update.service', 'HAVE_GNU_EFI'],
['systemd-coredump.socket', 'ENABLE_COREDUMP',

View File

@ -8,22 +8,21 @@
# (at your option) any later version.
[Unit]
Description=Store a System Token in an EFI Variable
Documentation=man:systemd-boot-system-token.service(8)
Description=Update Boot Loader Random Seed
Documentation=man:systemd-boot-random-seed.service(8) man:random(4)
DefaultDependencies=no
After=local-fs.target systemd-random-seed.service
Conflicts=shutdown.target initrd-switch-root.target
Before=shutdown.target initrd-switch-root.target
Conflicts=shutdown.target
Before=sysinit.target shutdown.target
ConditionVirtualization=!container
ConditionPathExists=!/etc/initrd-release
# Only run this if the boot loader can support random seed initialization.
ConditionPathExists=|/sys/firmware/efi/efivars/LoaderFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
ConditionPathExists=|/sys/firmware/efi/efivars/StubFeatures-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
# Only run this if there is no system token defined yet
ConditionPathExists=!/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=bootctl random-seed --graceful
ExecStart=bootctl --graceful random-seed

View File

@ -10,9 +10,10 @@
[Unit]
Description=Automatic Boot Loader Update
Documentation=man:bootctl(1)
DefaultDependencies=no
Conflicts=shutdown.target
After=local-fs.target
Conflicts=shutdown.target
Before=sysinit.target shutdown.target systemd-update-done.service
[Service]

View File

@ -8,14 +8,16 @@
# (at your option) any later version.
[Unit]
Description=Load/Save Random Seed
Description=Load/Save OS Random Seed
Documentation=man:systemd-random-seed.service(8) man:random(4)
DefaultDependencies=no
RequiresMountsFor={{RANDOM_SEED}}
Conflicts=shutdown.target
After=systemd-remount-fs.service
Before=first-boot-complete.target shutdown.target
Wants=first-boot-complete.target
ConditionVirtualization=!container
ConditionPathExists=!/etc/initrd-release