]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/efi-random.c
Merge pull request #16145 from poettering/qrcode-dlopen
[thirdparty/systemd.git] / src / core / efi-random.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <fcntl.h>
4 #include <unistd.h>
5
6 #include "alloc-util.h"
7 #include "chattr-util.h"
8 #include "efi-random.h"
9 #include "efivars.h"
10 #include "fd-util.h"
11 #include "fs-util.h"
12 #include "random-util.h"
13 #include "strv.h"
14
15 /* If a random seed was passed by the boot loader in the LoaderRandomSeed EFI variable, let's credit it to
16 * the kernel's random pool, but only once per boot. If this is run very early during initialization we can
17 * instantly boot up with a filled random pool.
18 *
19 * This makes no judgement on the entropy passed, it's the job of the boot loader to only pass us a seed that
20 * is suitably validated. */
21
22 static void lock_down_efi_variables(void) {
23 const char *p;
24 int r;
25
26 /* Paranoia: let's restrict access modes of these a bit, so that unprivileged users can't use them to
27 * identify the system or gain too much insight into what we might have credited to the entropy
28 * pool. */
29 FOREACH_STRING(p,
30 "/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f",
31 "/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f") {
32
33 r = chattr_path(p, 0, FS_IMMUTABLE_FL, NULL);
34 if (r == -ENOENT)
35 continue;
36 if (r < 0)
37 log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", p);
38
39 if (chmod(p, 0600) < 0)
40 log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", p);
41 }
42 }
43
44 int efi_take_random_seed(void) {
45 _cleanup_free_ void *value = NULL;
46 _cleanup_close_ int random_fd = -1;
47 size_t size;
48 int r;
49
50 /* Paranoia comes first. */
51 lock_down_efi_variables();
52
53 if (access("/run/systemd/efi-random-seed-taken", F_OK) < 0) {
54 if (errno != ENOENT) {
55 log_warning_errno(errno, "Failed to determine whether we already used the random seed token, not using it.");
56 return 0;
57 }
58
59 /* ENOENT means we haven't used it yet. */
60 } else {
61 log_debug("EFI random seed already used, not using again.");
62 return 0;
63 }
64
65 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderRandomSeed", NULL, &value, &size);
66 if (r == -EOPNOTSUPP) {
67 log_debug_errno(r, "System lacks EFI support, not initializing random seed from EFI variable.");
68 return 0;
69 }
70 if (r == -ENOENT) {
71 log_debug_errno(r, "Boot loader did not pass LoaderRandomSeed EFI variable, not crediting any entropy.");
72 return 0;
73 }
74 if (r < 0)
75 return log_warning_errno(r, "Failed to read LoaderRandomSeed EFI variable, ignoring: %m");
76
77 if (size == 0)
78 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring.");
79
80 random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
81 if (random_fd < 0)
82 return log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m");
83
84 /* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice
85 * way to let users known that we successfully acquired entropy from the boot laoder. */
86 r = touch("/run/systemd/efi-random-seed-taken");
87 if (r < 0)
88 return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m");
89
90 r = random_write_entropy(random_fd, value, size, true);
91 if (r < 0)
92 return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m");
93
94 log_info("Successfully credited entropy passed from boot loader.");
95 return 1;
96 }