]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/bootctl-random-seed.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / boot / bootctl-random-seed.c
CommitLineData
85f87535
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "alloc-util.h"
4#include "bootctl.h"
5#include "bootctl-random-seed.h"
6#include "bootctl-util.h"
7#include "efi-api.h"
8#include "env-util.h"
9#include "fd-util.h"
10#include "find-esp.h"
11#include "fs-util.h"
12#include "mkdir.h"
13#include "path-util.h"
14#include "random-util.h"
15#include "tmpfile-util.h"
16#include "umask-util.h"
17
18int install_random_seed(const char *esp) {
19 _cleanup_(unlink_and_freep) char *tmp = NULL;
20 uint8_t buffer[RANDOM_EFI_SEED_SIZE];
21 _cleanup_free_ char *path = NULL;
254d1313 22 _cleanup_close_ int fd = -EBADF;
85f87535
LP
23 size_t token_size;
24 ssize_t n;
25 int r;
26
27 assert(esp);
28
29 path = path_join(esp, "/loader/random-seed");
30 if (!path)
31 return log_oom();
32
33 r = crypto_random_bytes(buffer, sizeof(buffer));
34 if (r < 0)
35 return log_error_errno(r, "Failed to acquire random seed: %m");
36
37 /* Normally create_subdirs() should already have created everything we need, but in case "bootctl
38 * random-seed" is called we want to just create the minimum we need for it, and not the full
39 * list. */
40 r = mkdir_parents(path, 0755);
41 if (r < 0)
42 return log_error_errno(r, "Failed to create parent directory for %s: %m", path);
43
44 r = tempfn_random(path, "bootctl", &tmp);
45 if (r < 0)
46 return log_oom();
47
48 fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600);
49 if (fd < 0) {
50 tmp = mfree(tmp);
51 return log_error_errno(fd, "Failed to open random seed file for writing: %m");
52 }
53
54 n = write(fd, buffer, sizeof(buffer));
55 if (n < 0)
56 return log_error_errno(errno, "Failed to write random seed file: %m");
57 if ((size_t) n != sizeof(buffer))
58 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing random seed file.");
59
60 if (rename(tmp, path) < 0)
61 return log_error_errno(r, "Failed to move random seed file into place: %m");
62
63 tmp = mfree(tmp);
64
65 log_info("Random seed file %s successfully written (%zu bytes).", path, sizeof(buffer));
66
67 if (!arg_touch_variables)
68 return 0;
69
70 if (arg_root) {
71 log_warning("Acting on %s, skipping EFI variable setup.",
72 arg_image ? "image" : "root directory");
73 return 0;
74 }
75
76 if (!is_efi_boot()) {
77 log_notice("Not booted with EFI, skipping EFI variable setup.");
78 return 0;
79 }
80
81 r = getenv_bool("SYSTEMD_WRITE_SYSTEM_TOKEN");
82 if (r < 0) {
83 if (r != -ENXIO)
84 log_warning_errno(r, "Failed to parse $SYSTEMD_WRITE_SYSTEM_TOKEN, ignoring.");
85 } else if (r == 0) {
86 log_notice("Not writing system token, because $SYSTEMD_WRITE_SYSTEM_TOKEN is set to false.");
87 return 0;
88 }
89
90 r = efi_get_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), NULL, NULL, &token_size);
91 if (r == -ENODATA)
92 log_debug_errno(r, "LoaderSystemToken EFI variable is invalid (too short?), replacing.");
93 else if (r < 0) {
94 if (r != -ENOENT)
95 return log_error_errno(r, "Failed to test system token validity: %m");
96 } else {
97 if (token_size >= sizeof(buffer)) {
98 /* Let's avoid writes if we can, and initialize this only once. */
99 log_debug("System token already written, not updating.");
100 return 0;
101 }
102
103 log_debug("Existing system token size (%zu) does not match our expectations (%zu), replacing.", token_size, sizeof(buffer));
104 }
105
106 r = crypto_random_bytes(buffer, sizeof(buffer));
107 if (r < 0)
108 return log_error_errno(r, "Failed to acquire random seed: %m");
109
110 /* Let's write this variable with an umask in effect, so that unprivileged users can't see the token
111 * and possibly get identification information or too much insight into the kernel's entropy pool
112 * state. */
113 WITH_UMASK(0077) {
114 r = efi_set_variable(EFI_LOADER_VARIABLE(LoaderSystemToken), buffer, sizeof(buffer));
115 if (r < 0) {
116 if (!arg_graceful)
117 return log_error_errno(r, "Failed to write 'LoaderSystemToken' EFI variable: %m");
118
119 if (r == -EINVAL)
120 log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable (firmware problem?), ignoring: %m");
121 else
122 log_warning_errno(r, "Unable to write 'LoaderSystemToken' EFI variable, ignoring: %m");
123 } else
124 log_info("Successfully initialized system token in EFI variable with %zu bytes.", sizeof(buffer));
125 }
126
127 return 0;
128}
129
130int verb_random_seed(int argc, char *argv[], void *userdata) {
131 int r;
132
133 r = find_esp_and_warn(arg_root, arg_esp_path, false, &arg_esp_path, NULL, NULL, NULL, NULL, NULL);
134 if (r == -ENOKEY) {
135 /* find_esp_and_warn() doesn't warn about ENOKEY, so let's do that on our own */
136 if (!arg_graceful)
137 return log_error_errno(r, "Unable to find ESP.");
138
139 log_notice("No ESP found, not initializing random seed.");
140 return 0;
141 }
142 if (r < 0)
143 return r;
144
145 r = install_random_seed(arg_esp_path);
146 if (r < 0)
147 return r;
148
149 (void) sync_everything();
150 return 0;
151}