]>
Commit | Line | Data |
---|---|---|
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 | ||
18 | int 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 | ||
130 | int 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 | } |