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:
commit
e03fa62b63
@ -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>
|
||||
|
@ -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', [], ''],
|
||||
|
99
man/systemd-boot-random-seed.service.xml
Normal file
99
man/systemd-boot-random-seed.service.xml
Normal 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>
|
@ -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>
|
@ -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>,
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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]) {})
|
||||
|
@ -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);
|
||||
|
@ -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',
|
||||
|
@ -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
|
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user