]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/efi-random.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <linux/random.h>
8 #include "alloc-util.h"
9 #include "chattr-util.h"
10 #include "efi-random.h"
16 /* If a random seed was passed by the boot loader in the LoaderRandomSeed EFI variable, let's credit it to
17 * the kernel's random pool, but only once per boot. If this is run very early during initialization we can
18 * instantly boot up with a filled random pool.
20 * This makes no judgement on the entropy passed, it's the job of the boot loader to only pass us a seed that
21 * is suitably validated. */
23 static void lock_down_efi_variables(void) {
27 /* Paranoia: let's restrict access modes of these a bit, so that unprivileged users can't use them to
28 * identify the system or gain too much insight into what we might have credited to the entropy
31 "/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f",
32 "/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f") {
34 r
= chattr_path(p
, 0, FS_IMMUTABLE_FL
, NULL
);
38 log_warning_errno(r
, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", p
);
40 if (chmod(p
, 0600) < 0)
41 log_warning_errno(errno
, "Failed to reduce access mode of %s, ignoring: %m", p
);
45 int efi_take_random_seed(void) {
46 _cleanup_free_
struct rand_pool_info
*info
= NULL
;
47 _cleanup_free_
void *value
= NULL
;
48 _cleanup_close_
int random_fd
= -1;
52 /* Paranoia comes first. */
53 lock_down_efi_variables();
55 if (access("/run/systemd/efi-random-seed-taken", F_OK
) < 0) {
56 if (errno
!= ENOENT
) {
57 log_warning_errno(errno
, "Failed to determine whether we already used the random seed token, not using it.");
61 /* ENOENT means we haven't used it yet. */
63 log_debug("EFI random seed already used, not using again.");
67 r
= efi_get_variable(EFI_VENDOR_LOADER
, "LoaderRandomSeed", NULL
, &value
, &size
);
68 if (r
== -EOPNOTSUPP
) {
69 log_debug_errno(r
, "System lacks EFI support, not initializing random seed from EFI variable.");
73 log_debug_errno(r
, "Boot loader did not pass LoaderRandomSeed EFI variable, not crediting any entropy.");
77 return log_warning_errno(r
, "Failed to read LoaderRandomSeed EFI variable, ignoring: %m");
80 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
), "Random seed passed from boot loader has zero size? Ignoring.");
82 /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any chance for
84 if (size
> INT_MAX
/ 8)
87 random_fd
= open("/dev/urandom", O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
89 return log_warning_errno(errno
, "Failed to open /dev/urandom for writing, ignoring: %m");
91 /* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice
92 * way to let users known that we successfully acquired entropy from the boot laoder. */
93 r
= touch("/run/systemd/efi-random-seed-taken");
95 return log_warning_errno(r
, "Unable to mark EFI random seed as used, not using it: %m");
97 info
= malloc(offsetof(struct rand_pool_info
, buf
) + size
);
101 info
->entropy_count
= size
* 8;
102 info
->buf_size
= size
;
103 memcpy(info
->buf
, value
, size
);
105 if (ioctl(random_fd
, RNDADDENTROPY
, info
) < 0)
106 return log_warning_errno(errno
, "Failed to credit entropy, ignoring: %m");
108 log_info("Successfully credited entropy passed from boot loader.");