Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <fcntl.h>
4 : : #include <linux/random.h>
5 : : #include <sys/ioctl.h>
6 : : #include <unistd.h>
7 : :
8 : : #include "alloc-util.h"
9 : : #include "chattr-util.h"
10 : : #include "efi-random.h"
11 : : #include "efivars.h"
12 : : #include "fd-util.h"
13 : : #include "fs-util.h"
14 : : #include "strv.h"
15 : :
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.
19 : : *
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. */
22 : :
23 : 0 : static void lock_down_efi_variables(void) {
24 : : const char *p;
25 : : int r;
26 : :
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
29 : : * pool. */
30 [ # # ]: 0 : FOREACH_STRING(p,
31 : : "/sys/firmware/efi/efivars/LoaderRandomSeed-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f",
32 : : "/sys/firmware/efi/efivars/LoaderSystemToken-4a67b082-0a4c-41cf-b6c7-440b29bb8c4f") {
33 : :
34 : 0 : r = chattr_path(p, 0, FS_IMMUTABLE_FL, NULL);
35 [ # # ]: 0 : if (r == -ENOENT)
36 : 0 : continue;
37 [ # # ]: 0 : if (r < 0)
38 [ # # ]: 0 : log_warning_errno(r, "Failed to drop FS_IMMUTABLE_FL from %s, ignoring: %m", p);
39 : :
40 [ # # ]: 0 : if (chmod(p, 0600) < 0)
41 [ # # ]: 0 : log_warning_errno(errno, "Failed to reduce access mode of %s, ignoring: %m", p);
42 : : }
43 : 0 : }
44 : :
45 : 0 : int efi_take_random_seed(void) {
46 : 0 : _cleanup_free_ struct rand_pool_info *info = NULL;
47 : 0 : _cleanup_free_ void *value = NULL;
48 : 0 : _cleanup_close_ int random_fd = -1;
49 : : size_t size;
50 : : int r;
51 : :
52 : : /* Paranoia comes first. */
53 : 0 : lock_down_efi_variables();
54 : :
55 [ # # ]: 0 : if (access("/run/systemd/efi-random-seed-taken", F_OK) < 0) {
56 [ # # ]: 0 : if (errno != ENOENT) {
57 [ # # ]: 0 : log_warning_errno(errno, "Failed to determine whether we already used the random seed token, not using it.");
58 : 0 : return 0;
59 : : }
60 : :
61 : : /* ENOENT means we haven't used it yet. */
62 : : } else {
63 [ # # ]: 0 : log_debug("EFI random seed already used, not using again.");
64 : 0 : return 0;
65 : : }
66 : :
67 : 0 : r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderRandomSeed", NULL, &value, &size);
68 [ # # ]: 0 : if (r == -EOPNOTSUPP) {
69 [ # # ]: 0 : log_debug_errno(r, "System lacks EFI support, not initializing random seed from EFI variable.");
70 : 0 : return 0;
71 : : }
72 [ # # ]: 0 : if (r == -ENOENT) {
73 [ # # ]: 0 : log_debug_errno(r, "Boot loader did not pass LoaderRandomSeed EFI variable, not crediting any entropy.");
74 : 0 : return 0;
75 : : }
76 [ # # ]: 0 : if (r < 0)
77 [ # # ]: 0 : return log_warning_errno(r, "Failed to read LoaderRandomSeed EFI variable, ignoring: %m");
78 : :
79 [ # # ]: 0 : if (size == 0)
80 [ # # ]: 0 : return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring.");
81 : :
82 : : /* The kernel API only accepts "int" as entropy count (which is in bits), let's avoid any chance for
83 : : * confusion here. */
84 [ # # ]: 0 : if (size > INT_MAX / 8)
85 : 0 : size = INT_MAX / 8;
86 : :
87 : 0 : random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY);
88 [ # # ]: 0 : if (random_fd < 0)
89 [ # # ]: 0 : return log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m");
90 : :
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 : 0 : r = touch("/run/systemd/efi-random-seed-taken");
94 [ # # ]: 0 : if (r < 0)
95 [ # # ]: 0 : return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m");
96 : :
97 : 0 : info = malloc(offsetof(struct rand_pool_info, buf) + size);
98 [ # # ]: 0 : if (!info)
99 : 0 : return log_oom();
100 : :
101 : 0 : info->entropy_count = size * 8;
102 : 0 : info->buf_size = size;
103 : 0 : memcpy(info->buf, value, size);
104 : :
105 [ # # ]: 0 : if (ioctl(random_fd, RNDADDENTROPY, info) < 0)
106 [ # # ]: 0 : return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m");
107 : :
108 [ # # ]: 0 : log_info("Successfully credited entropy passed from boot loader.");
109 : 0 : return 1;
110 : : }
|