1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <linux/fs.h>
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 
11 #include "sd-id128.h"
12 
13 #include "alloc-util.h"
14 #include "chattr-util.h"
15 #include "efivars.h"
16 #include "fd-util.h"
17 #include "fileio.h"
18 #include "io-util.h"
19 #include "macro.h"
20 #include "memory-util.h"
21 #include "stdio-util.h"
22 #include "strv.h"
23 #include "time-util.h"
24 #include "utf8.h"
25 #include "virt.h"
26 
27 #if ENABLE_EFI
28 
29 /* Reads from efivarfs sometimes fail with EINTR. Retry that many times. */
30 #define EFI_N_RETRIES_NO_DELAY 20
31 #define EFI_N_RETRIES_TOTAL 25
32 #define EFI_RETRY_DELAY (50 * USEC_PER_MSEC)
33 
efi_get_variable(const char * variable,uint32_t * ret_attribute,void ** ret_value,size_t * ret_size)34 int efi_get_variable(
35                 const char *variable,
36                 uint32_t *ret_attribute,
37                 void **ret_value,
38                 size_t *ret_size) {
39 
40         _cleanup_close_ int fd = -1;
41         _cleanup_free_ void *buf = NULL;
42         struct stat st;
43         usec_t begin = 0; /* Unnecessary initialization to appease gcc */
44         uint32_t a;
45         ssize_t n;
46 
47         assert(variable);
48 
49         const char *p = strjoina("/sys/firmware/efi/efivars/", variable);
50 
51         if (!ret_value && !ret_size && !ret_attribute) {
52                 /* If caller is not interested in anything, just check if the variable exists and is
53                  * readable. */
54                 if (access(p, R_OK) < 0)
55                         return -errno;
56 
57                 return 0;
58         }
59 
60         if (DEBUG_LOGGING) {
61                 log_debug("Reading EFI variable %s.", p);
62                 begin = now(CLOCK_MONOTONIC);
63         }
64 
65         fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
66         if (fd < 0)
67                 return log_debug_errno(errno, "open(\"%s\") failed: %m", p);
68 
69         if (fstat(fd, &st) < 0)
70                 return log_debug_errno(errno, "fstat(\"%s\") failed: %m", p);
71         if (st.st_size < 4)
72                 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA), "EFI variable %s is shorter than 4 bytes, refusing.", p);
73         if (st.st_size > 4*1024*1024 + 4)
74                 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG), "EFI variable %s is ridiculously large, refusing.", p);
75 
76         if (ret_value || ret_attribute) {
77                 /* The kernel ratelimits reads from the efivarfs because EFI is inefficient, and we'll
78                  * occasionally fail with EINTR here. A slowdown is better than a failure for us, so
79                  * retry a few times and eventually fail with -EBUSY.
80                  *
81                  * See https://github.com/torvalds/linux/blob/master/fs/efivarfs/file.c#L75
82                  * and
83                  * https://github.com/torvalds/linux/commit/bef3efbeb897b56867e271cdbc5f8adaacaeb9cd.
84                  */
85                 for (unsigned try = 0;; try++) {
86                         n = read(fd, &a, sizeof(a));
87                         if (n >= 0)
88                                 break;
89                         log_debug_errno(errno, "Reading from \"%s\" failed: %m", p);
90                         if (errno != EINTR)
91                                 return -errno;
92                         if (try >= EFI_N_RETRIES_TOTAL)
93                                 return -EBUSY;
94 
95                         if (try >= EFI_N_RETRIES_NO_DELAY)
96                                 (void) usleep(EFI_RETRY_DELAY);
97                 }
98 
99                 if (n != sizeof(a))
100                         return log_debug_errno(SYNTHETIC_ERRNO(EIO),
101                                                "Read %zi bytes from EFI variable %s, expected %zu.",  n, p, sizeof(a));
102         }
103 
104         if (ret_value) {
105                 buf = malloc(st.st_size - 4 + 3);
106                 if (!buf)
107                         return -ENOMEM;
108 
109                 n = read(fd, buf, (size_t) st.st_size - 4);
110                 if (n < 0)
111                         return log_debug_errno(errno, "Failed to read value of EFI variable %s: %m", p);
112                 assert(n <= st.st_size - 4);
113 
114                 /* Always NUL-terminate (3 bytes, to properly protect UTF-16, even if truncated in the middle
115                  * of a character) */
116                 ((char*) buf)[n] = 0;
117                 ((char*) buf)[n + 1] = 0;
118                 ((char*) buf)[n + 2] = 0;
119         } else
120                 /* Assume that the reported size is accurate */
121                 n = st.st_size - 4;
122 
123         if (DEBUG_LOGGING) {
124                 usec_t end = now(CLOCK_MONOTONIC);
125                 if (end > begin + EFI_RETRY_DELAY)
126                         log_debug("Detected slow EFI variable read access on %s: %s",
127                                   variable, FORMAT_TIMESPAN(end - begin, 1));
128         }
129 
130         /* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable
131          * with a smaller value. */
132 
133         if (ret_attribute)
134                 *ret_attribute = a;
135 
136         if (ret_value)
137                 *ret_value = TAKE_PTR(buf);
138 
139         if (ret_size)
140                 *ret_size = n;
141 
142         return 0;
143 }
144 
efi_get_variable_string(const char * variable,char ** ret)145 int efi_get_variable_string(const char *variable, char **ret) {
146         _cleanup_free_ void *s = NULL;
147         size_t ss = 0;
148         int r;
149         char *x;
150 
151         r = efi_get_variable(variable, NULL, &s, &ss);
152         if (r < 0)
153                 return r;
154 
155         x = utf16_to_utf8(s, ss);
156         if (!x)
157                 return -ENOMEM;
158 
159         *ret = x;
160         return 0;
161 }
162 
efi_verify_variable(const char * variable,uint32_t attr,const void * value,size_t size)163 static int efi_verify_variable(const char *variable, uint32_t attr, const void *value, size_t size) {
164         _cleanup_free_ void *buf = NULL;
165         size_t n;
166         uint32_t a;
167         int r;
168 
169         assert(variable);
170         assert(value || size == 0);
171 
172         r = efi_get_variable(variable, &a, &buf, &n);
173         if (r < 0)
174                 return r;
175 
176         return a == attr && memcmp_nn(buf, n, value, size) == 0;
177 }
178 
efi_set_variable(const char * variable,const void * value,size_t size)179 int efi_set_variable(const char *variable, const void *value, size_t size) {
180         struct var {
181                 uint32_t attr;
182                 char buf[];
183         } _packed_ * _cleanup_free_ buf = NULL;
184         _cleanup_close_ int fd = -1;
185         uint32_t attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
186         bool saved_flags_valid = false;
187         unsigned saved_flags;
188         int r;
189 
190         assert(variable);
191         assert(value || size == 0);
192 
193         const char *p = strjoina("/sys/firmware/efi/efivars/", variable);
194 
195         /* size 0 means removal, empty variable would not be enough for that */
196         if (size > 0 && efi_verify_variable(variable, attr, value, size) > 0) {
197                 log_debug("Variable '%s' is already in wanted state, skipping write.", variable);
198                 return 0;
199         }
200 
201         /* Newer efivarfs protects variables that are not in an allow list with FS_IMMUTABLE_FL by default,
202          * to protect them for accidental removal and modification. We are not changing these variables
203          * accidentally however, hence let's unset the bit first. */
204 
205         r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags);
206         if (r < 0 && r != -ENOENT)
207                 log_debug_errno(r, "Failed to drop FS_IMMUTABLE_FL flag from '%s', ignoring: %m", p);
208 
209         saved_flags_valid = r >= 0;
210 
211         if (size == 0) {
212                 if (unlink(p) < 0) {
213                         r = -errno;
214                         goto finish;
215                 }
216 
217                 return 0;
218         }
219 
220         fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
221         if (fd < 0) {
222                 r = -errno;
223                 goto finish;
224         }
225 
226         buf = malloc(sizeof(uint32_t) + size);
227         if (!buf) {
228                 r = -ENOMEM;
229                 goto finish;
230         }
231 
232         buf->attr = attr;
233         memcpy(buf->buf, value, size);
234 
235         r = loop_write(fd, buf, sizeof(uint32_t) + size, false);
236         if (r < 0)
237                 goto finish;
238 
239         /* For some reason efivarfs doesn't update mtime automatically. Let's do it manually then. This is
240          * useful for processes that cache EFI variables to detect when changes occurred. */
241         if (futimens(fd, (struct timespec[2]) {
242                                 { .tv_nsec = UTIME_NOW },
243                                 { .tv_nsec = UTIME_NOW }
244                         }) < 0)
245                 log_debug_errno(errno, "Failed to update mtime/atime on %s, ignoring: %m", p);
246 
247         r = 0;
248 
249 finish:
250         if (saved_flags_valid) {
251                 int q;
252 
253                 /* Restore the original flags field, just in case */
254                 if (fd < 0)
255                         q = chattr_path(p, saved_flags, FS_IMMUTABLE_FL, NULL);
256                 else
257                         q = chattr_fd(fd, saved_flags, FS_IMMUTABLE_FL, NULL);
258                 if (q < 0)
259                         log_debug_errno(q, "Failed to restore FS_IMMUTABLE_FL on '%s', ignoring: %m", p);
260         }
261 
262         return r;
263 }
264 
efi_set_variable_string(const char * variable,const char * value)265 int efi_set_variable_string(const char *variable, const char *value) {
266         _cleanup_free_ char16_t *u16 = NULL;
267 
268         u16 = utf8_to_utf16(value, strlen(value));
269         if (!u16)
270                 return -ENOMEM;
271 
272         return efi_set_variable(variable, u16, (char16_strlen(u16) + 1) * sizeof(char16_t));
273 }
274 
is_efi_boot(void)275 bool is_efi_boot(void) {
276         static int cache = -1;
277 
278         if (cache < 0) {
279                 if (detect_container() > 0)
280                         cache = false;
281                 else {
282                         cache = access("/sys/firmware/efi/", F_OK) >= 0;
283                         if (!cache && errno != ENOENT)
284                                 log_debug_errno(errno, "Unable to test whether /sys/firmware/efi/ exists, assuming EFI not available: %m");
285                 }
286         }
287 
288         return cache;
289 }
290 
read_flag(const char * variable)291 static int read_flag(const char *variable) {
292         _cleanup_free_ void *v = NULL;
293         uint8_t b;
294         size_t s;
295         int r;
296 
297         if (!is_efi_boot()) /* If this is not an EFI boot, assume the queried flags are zero */
298                 return 0;
299 
300         r = efi_get_variable(variable, NULL, &v, &s);
301         if (r < 0)
302                 return r;
303 
304         if (s != 1)
305                 return -EINVAL;
306 
307         b = *(uint8_t *)v;
308         return !!b;
309 }
310 
is_efi_secure_boot(void)311 bool is_efi_secure_boot(void) {
312         static int cache = -1;
313         int r;
314 
315         if (cache < 0) {
316                 r = read_flag(EFI_GLOBAL_VARIABLE(SecureBoot));
317                 if (r == -ENOENT)
318                         cache = false;
319                 else if (r < 0)
320                         log_debug_errno(r, "Error reading SecureBoot EFI variable, assuming not in SecureBoot mode: %m");
321                 else
322                         cache = r;
323         }
324 
325         return cache > 0;
326 }
327 
efi_get_secure_boot_mode(void)328 SecureBootMode efi_get_secure_boot_mode(void) {
329         static SecureBootMode cache = _SECURE_BOOT_INVALID;
330 
331         if (cache != _SECURE_BOOT_INVALID)
332                 return cache;
333 
334         int secure = read_flag(EFI_GLOBAL_VARIABLE(SecureBoot));
335         if (secure < 0) {
336                 if (secure != -ENOENT)
337                         log_debug_errno(secure, "Error reading SecureBoot EFI variable, assuming not in SecureBoot mode: %m");
338 
339                 return (cache = SECURE_BOOT_UNSUPPORTED);
340         }
341 
342         /* We can assume false for all these if they are abscent (AuditMode and
343          * DeployedMode may not exist on older firmware). */
344         int audit    = read_flag(EFI_GLOBAL_VARIABLE(AuditMode));
345         int deployed = read_flag(EFI_GLOBAL_VARIABLE(DeployedMode));
346         int setup    = read_flag(EFI_GLOBAL_VARIABLE(SetupMode));
347         log_debug("Secure boot variables: SecureBoot=%d AuditMode=%d DeployedMode=%d SetupMode=%d",
348                   secure, audit, deployed, setup);
349 
350         return (cache = decode_secure_boot_mode(secure, audit > 0, deployed > 0, setup > 0));
351 }
352 
read_efi_options_variable(char ** ret)353 static int read_efi_options_variable(char **ret) {
354         int r;
355 
356         /* In SecureBoot mode this is probably not what you want. As your cmdline is cryptographically signed
357          * like when using Type #2 EFI Unified Kernel Images (https://systemd.io/BOOT_LOADER_SPECIFICATION)
358          * The user's intention is then that the cmdline should not be modified. You want to make sure that
359          * the system starts up as exactly specified in the signed artifact.
360          *
361          * (NB: For testing purposes, we still check the $SYSTEMD_EFI_OPTIONS env var before accessing this
362          * cache, even when in SecureBoot mode.) */
363         if (is_efi_secure_boot()) {
364                 /* Let's be helpful with the returned error and check if the variable exists at all. If it
365                  * does, let's return a recognizable error (EPERM), and if not ENODATA. */
366 
367                 if (access(EFIVAR_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), F_OK) < 0)
368                         return errno == ENOENT ? -ENODATA : -errno;
369 
370                 return -EPERM;
371         }
372 
373         r = efi_get_variable_string(EFI_SYSTEMD_VARIABLE(SystemdOptions), ret);
374         if (r == -ENOENT)
375                 return -ENODATA;
376         return r;
377 }
378 
cache_efi_options_variable(void)379 int cache_efi_options_variable(void) {
380         _cleanup_free_ char *line = NULL;
381         int r;
382 
383         r = read_efi_options_variable(&line);
384         if (r < 0)
385                 return r;
386 
387         return write_string_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), line,
388                                  WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755);
389 }
390 
systemd_efi_options_variable(char ** ret)391 int systemd_efi_options_variable(char **ret) {
392         const char *e;
393         int r;
394 
395         /* Returns the contents of the variable for current boot from the cache. */
396 
397         assert(ret);
398 
399         /* For testing purposes it is sometimes useful to be able to override this */
400         e = secure_getenv("SYSTEMD_EFI_OPTIONS");
401         if (e) {
402                 char *m;
403 
404                 m = strdup(e);
405                 if (!m)
406                         return -ENOMEM;
407 
408                 *ret = m;
409                 return 0;
410         }
411 
412         r = read_one_line_file(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), ret);
413         if (r == -ENOENT)
414                 return -ENODATA;
415         return r;
416 }
417 
compare_stat_mtime(const struct stat * a,const struct stat * b)418 static inline int compare_stat_mtime(const struct stat *a, const struct stat *b) {
419         return CMP(timespec_load(&a->st_mtim), timespec_load(&b->st_mtim));
420 }
421 
systemd_efi_options_efivarfs_if_newer(char ** ret)422 int systemd_efi_options_efivarfs_if_newer(char **ret) {
423         struct stat a = {}, b;
424         int r;
425 
426         if (stat(EFIVAR_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), &a) < 0 && errno != ENOENT)
427                 return log_debug_errno(errno, "Failed to stat EFI variable SystemdOptions: %m");
428 
429         if (stat(EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions)), &b) < 0) {
430                 if (errno != ENOENT)
431                         log_debug_errno(errno, "Failed to stat "EFIVAR_CACHE_PATH(EFI_SYSTEMD_VARIABLE(SystemdOptions))": %m");
432         } else if (compare_stat_mtime(&a, &b) > 0)
433                 log_debug("Variable SystemdOptions in evifarfs is newer than in cache.");
434         else {
435                 log_debug("Variable SystemdOptions in cache is up to date.");
436                 *ret = NULL;
437                 return 0;
438         }
439 
440         r = read_efi_options_variable(ret);
441         if (r < 0)
442                 return log_debug_errno(r, "Failed to read SystemdOptions EFI variable: %m");
443 
444         return 0;
445 }
446 #endif
447