]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efivars.c
Merge pull request #13365 from keszybz/fix-commits-from-pr-13246
[thirdparty/systemd.git] / src / shared / efivars.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <dirent.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <limits.h>
7 #include <linux/fs.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13
14 #include "sd-id128.h"
15
16 #include "alloc-util.h"
17 #include "chattr-util.h"
18 #include "dirent-util.h"
19 #include "efivars.h"
20 #include "fd-util.h"
21 #include "io-util.h"
22 #include "macro.h"
23 #include "parse-util.h"
24 #include "sort-util.h"
25 #include "stdio-util.h"
26 #include "strv.h"
27 #include "time-util.h"
28 #include "utf8.h"
29 #include "virt.h"
30
31 #if ENABLE_EFI
32
33 #define LOAD_OPTION_ACTIVE 0x00000001
34 #define MEDIA_DEVICE_PATH 0x04
35 #define MEDIA_HARDDRIVE_DP 0x01
36 #define MEDIA_FILEPATH_DP 0x04
37 #define SIGNATURE_TYPE_GUID 0x02
38 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
39 #define END_DEVICE_PATH_TYPE 0x7f
40 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
41 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
42
43 #define boot_option__contents { \
44 uint32_t attr; \
45 uint16_t path_len; \
46 uint16_t title[]; \
47 }
48
49 struct boot_option boot_option__contents;
50 struct boot_option__packed boot_option__contents _packed_;
51 assert_cc(offsetof(struct boot_option, title) == offsetof(struct boot_option__packed, title));
52 /* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so
53 * the *size* of the structure should not be used anywhere below. */
54
55 struct drive_path {
56 uint32_t part_nr;
57 uint64_t part_start;
58 uint64_t part_size;
59 char signature[16];
60 uint8_t mbr_type;
61 uint8_t signature_type;
62 } _packed_;
63
64 #define device_path__contents { \
65 uint8_t type; \
66 uint8_t sub_type; \
67 uint16_t length; \
68 union { \
69 uint16_t path[0]; \
70 struct drive_path drive; \
71 }; \
72 }
73
74 struct device_path device_path__contents;
75 struct device_path__packed device_path__contents _packed_;
76 assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed));
77
78 bool is_efi_boot(void) {
79 if (detect_container() > 0)
80 return false;
81
82 return access("/sys/firmware/efi/", F_OK) >= 0;
83 }
84
85 static int read_flag(const char *varname) {
86 _cleanup_free_ void *v = NULL;
87 uint8_t b;
88 size_t s;
89 int r;
90
91 if (!is_efi_boot()) /* If this is not an EFI boot, assume the queried flags are zero */
92 return 0;
93
94 r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
95 if (r < 0)
96 return r;
97
98 if (s != 1)
99 return -EINVAL;
100
101 b = *(uint8_t *)v;
102 return !!b;
103 }
104
105 bool is_efi_secure_boot(void) {
106 return read_flag("SecureBoot") > 0;
107 }
108
109 bool is_efi_secure_boot_setup_mode(void) {
110 return read_flag("SetupMode") > 0;
111 }
112
113 int efi_reboot_to_firmware_supported(void) {
114 _cleanup_free_ void *v = NULL;
115 uint64_t b;
116 size_t s;
117 int r;
118
119 if (!is_efi_boot())
120 return -EOPNOTSUPP;
121
122 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
123 if (r == -ENOENT) /* variable doesn't exist? it's not supported then */
124 return -EOPNOTSUPP;
125 if (r < 0)
126 return r;
127 if (s != sizeof(uint64_t))
128 return -EINVAL;
129
130 b = *(uint64_t*) v;
131 if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
132 return -EOPNOTSUPP; /* bit unset? it's not supported then */
133
134 return 0;
135 }
136
137 static int get_os_indications(uint64_t *os_indication) {
138 _cleanup_free_ void *v = NULL;
139 size_t s;
140 int r;
141
142 /* Let's verify general support first */
143 r = efi_reboot_to_firmware_supported();
144 if (r < 0)
145 return r;
146
147 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
148 if (r == -ENOENT) {
149 /* Some firmware implementations that do support OsIndications and report that with
150 * OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's pretend it's 0
151 * then, to hide this implementation detail. Note that this call will return -ENOENT then only if the
152 * support for OsIndications is missing entirely, as determined by efi_reboot_to_firmware_supported()
153 * above. */
154 *os_indication = 0;
155 return 0;
156 } else if (r < 0)
157 return r;
158 else if (s != sizeof(uint64_t))
159 return -EINVAL;
160
161 *os_indication = *(uint64_t *)v;
162 return 0;
163 }
164
165 int efi_get_reboot_to_firmware(void) {
166 int r;
167 uint64_t b;
168
169 r = get_os_indications(&b);
170 if (r < 0)
171 return r;
172
173 return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
174 }
175
176 int efi_set_reboot_to_firmware(bool value) {
177 int r;
178 uint64_t b, b_new;
179
180 r = get_os_indications(&b);
181 if (r < 0)
182 return r;
183
184 if (value)
185 b_new = b | EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
186 else
187 b_new = b & ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
188
189 /* Avoid writing to efi vars store if we can due to firmware bugs. */
190 if (b != b_new)
191 return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t));
192
193 return 0;
194 }
195
196 char* efi_variable_path(sd_id128_t vendor, const char *name) {
197 char *p;
198
199 if (asprintf(&p,
200 "/sys/firmware/efi/efivars/%s-" SD_ID128_UUID_FORMAT_STR,
201 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
202 return NULL;
203
204 return p;
205 }
206
207 int efi_get_variable(
208 sd_id128_t vendor,
209 const char *name,
210 uint32_t *ret_attribute,
211 void **ret_value,
212 size_t *ret_size) {
213
214 _cleanup_close_ int fd = -1;
215 _cleanup_free_ char *p = NULL;
216 _cleanup_free_ void *buf = NULL;
217 struct stat st;
218 uint32_t a;
219 ssize_t n;
220
221 assert(name);
222
223 p = efi_variable_path(vendor, name);
224 if (!p)
225 return -ENOMEM;
226
227 if (!ret_value && !ret_size && !ret_attribute) {
228 /* If caller is not interested in anything, just check if the variable exists and is readable
229 * to us. */
230 if (access(p, R_OK) < 0)
231 return -errno;
232
233 return 0;
234 }
235
236 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
237 if (fd < 0)
238 return -errno;
239
240 if (fstat(fd, &st) < 0)
241 return -errno;
242 if (st.st_size < 4)
243 return -ENODATA;
244 if (st.st_size > 4*1024*1024 + 4)
245 return -E2BIG;
246
247 if (ret_value || ret_attribute) {
248 n = read(fd, &a, sizeof(a));
249 if (n < 0)
250 return -errno;
251 if (n != sizeof(a))
252 return -EIO;
253 }
254
255 if (ret_value) {
256 buf = malloc(st.st_size - 4 + 2);
257 if (!buf)
258 return -ENOMEM;
259
260 n = read(fd, buf, (size_t) st.st_size - 4);
261 if (n < 0)
262 return -errno;
263 if (n != st.st_size - 4)
264 return -EIO;
265
266 /* Always NUL terminate (2 bytes, to protect UTF-16) */
267 ((char*) buf)[st.st_size - 4] = 0;
268 ((char*) buf)[st.st_size - 4 + 1] = 0;
269 }
270
271 /* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable
272 * with a smaller value. */
273
274 if (ret_attribute)
275 *ret_attribute = a;
276
277 if (ret_value)
278 *ret_value = TAKE_PTR(buf);
279
280 if (ret_size)
281 *ret_size = (size_t) st.st_size - 4;
282
283 return 0;
284 }
285
286 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
287 _cleanup_free_ void *s = NULL;
288 size_t ss = 0;
289 int r;
290 char *x;
291
292 r = efi_get_variable(vendor, name, NULL, &s, &ss);
293 if (r < 0)
294 return r;
295
296 x = utf16_to_utf8(s, ss);
297 if (!x)
298 return -ENOMEM;
299
300 *p = x;
301 return 0;
302 }
303
304 int efi_set_variable(
305 sd_id128_t vendor,
306 const char *name,
307 const void *value,
308 size_t size) {
309
310 struct var {
311 uint32_t attr;
312 char buf[];
313 } _packed_ * _cleanup_free_ buf = NULL;
314 _cleanup_free_ char *p = NULL;
315 _cleanup_close_ int fd = -1;
316 bool saved_flags_valid = false;
317 unsigned saved_flags;
318 int r;
319
320 assert(name);
321 assert(value || size == 0);
322
323 p = efi_variable_path(vendor, name);
324 if (!p)
325 return -ENOMEM;
326
327 /* Newer efivarfs protects variables that are not in a whitelist with FS_IMMUTABLE_FL by default, to protect
328 * them for accidental removal and modification. We are not changing these variables accidentally however,
329 * hence let's unset the bit first. */
330
331 r = chattr_path(p, 0, FS_IMMUTABLE_FL, &saved_flags);
332 if (r < 0 && r != -ENOENT)
333 log_debug_errno(r, "Failed to drop FS_IMMUTABLE_FL flag from '%s', ignoring: %m", p);
334
335 saved_flags_valid = r >= 0;
336
337 if (size == 0) {
338 if (unlink(p) < 0) {
339 r = -errno;
340 goto finish;
341 }
342
343 return 0;
344 }
345
346 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
347 if (fd < 0) {
348 r = -errno;
349 goto finish;
350 }
351
352 buf = malloc(sizeof(uint32_t) + size);
353 if (!buf) {
354 r = -ENOMEM;
355 goto finish;
356 }
357
358 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
359 memcpy(buf->buf, value, size);
360
361 r = loop_write(fd, buf, sizeof(uint32_t) + size, false);
362 if (r < 0)
363 goto finish;
364
365 r = 0;
366
367 finish:
368 if (saved_flags_valid) {
369 int q;
370
371 /* Restore the original flags field, just in case */
372 if (fd < 0)
373 q = chattr_path(p, saved_flags, FS_IMMUTABLE_FL, NULL);
374 else
375 q = chattr_fd(fd, saved_flags, FS_IMMUTABLE_FL, NULL);
376 if (q < 0)
377 log_debug_errno(q, "Failed to restore FS_IMMUTABLE_FL on '%s', ignoring: %m", p);
378 }
379
380 return r;
381 }
382
383 int efi_set_variable_string(sd_id128_t vendor, const char *name, const char *v) {
384 _cleanup_free_ char16_t *u16 = NULL;
385
386 u16 = utf8_to_utf16(v, strlen(v));
387 if (!u16)
388 return -ENOMEM;
389
390 return efi_set_variable(vendor, name, u16, (char16_strlen(u16) + 1) * sizeof(char16_t));
391 }
392
393 static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) {
394 size_t l = 0;
395
396 /* Returns the size of the string in bytes without the terminating two zero bytes */
397
398 if (buf_len_bytes % sizeof(uint16_t) != 0)
399 return -EINVAL;
400
401 while (l < buf_len_bytes / sizeof(uint16_t)) {
402 if (s[l] == 0)
403 return (l + 1) * sizeof(uint16_t);
404 l++;
405 }
406
407 return -EINVAL; /* The terminator was not found */
408 }
409
410 struct guid {
411 uint32_t u1;
412 uint16_t u2;
413 uint16_t u3;
414 uint8_t u4[8];
415 } _packed_;
416
417 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
418 uint32_t u1;
419 uint16_t u2, u3;
420 const struct guid *uuid = guid;
421
422 memcpy(&u1, &uuid->u1, sizeof(uint32_t));
423 id128->bytes[0] = (u1 >> 24) & 0xff;
424 id128->bytes[1] = (u1 >> 16) & 0xff;
425 id128->bytes[2] = (u1 >> 8) & 0xff;
426 id128->bytes[3] = u1 & 0xff;
427 memcpy(&u2, &uuid->u2, sizeof(uint16_t));
428 id128->bytes[4] = (u2 >> 8) & 0xff;
429 id128->bytes[5] = u2 & 0xff;
430 memcpy(&u3, &uuid->u3, sizeof(uint16_t));
431 id128->bytes[6] = (u3 >> 8) & 0xff;
432 id128->bytes[7] = u3 & 0xff;
433 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
434 }
435
436 int efi_get_boot_option(
437 uint16_t id,
438 char **title,
439 sd_id128_t *part_uuid,
440 char **path,
441 bool *active) {
442
443 char boot_id[9];
444 _cleanup_free_ uint8_t *buf = NULL;
445 size_t l;
446 struct boot_option *header;
447 ssize_t title_size;
448 _cleanup_free_ char *s = NULL, *p = NULL;
449 sd_id128_t p_uuid = SD_ID128_NULL;
450 int r;
451
452 if (!is_efi_boot())
453 return -EOPNOTSUPP;
454
455 xsprintf(boot_id, "Boot%04X", id);
456 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
457 if (r < 0)
458 return r;
459 if (l < offsetof(struct boot_option, title))
460 return -ENOENT;
461
462 header = (struct boot_option *)buf;
463 title_size = utf16_size(header->title, l - offsetof(struct boot_option, title));
464 if (title_size < 0)
465 return title_size;
466
467 if (title) {
468 s = utf16_to_utf8(header->title, title_size);
469 if (!s)
470 return -ENOMEM;
471 }
472
473 if (header->path_len > 0) {
474 uint8_t *dbuf;
475 size_t dnext, doff;
476
477 doff = offsetof(struct boot_option, title) + title_size;
478 dbuf = buf + doff;
479 if (header->path_len > l - doff)
480 return -EINVAL;
481
482 dnext = 0;
483 while (dnext < header->path_len) {
484 struct device_path *dpath;
485
486 dpath = (struct device_path *)(dbuf + dnext);
487 if (dpath->length < 4)
488 break;
489
490 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
491 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
492 break;
493
494 dnext += dpath->length;
495
496 /* Type 0x04 – Media Device Path */
497 if (dpath->type != MEDIA_DEVICE_PATH)
498 continue;
499
500 /* Sub-Type 1 – Hard Drive */
501 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
502 /* 0x02 – GUID Partition Table */
503 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
504 continue;
505
506 /* 0x02 – GUID signature */
507 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
508 continue;
509
510 if (part_uuid)
511 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
512 continue;
513 }
514
515 /* Sub-Type 4 – File Path */
516 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
517 p = utf16_to_utf8(dpath->path, dpath->length-4);
518 if (!p)
519 return -ENOMEM;
520
521 efi_tilt_backslashes(p);
522 continue;
523 }
524 }
525 }
526
527 if (title)
528 *title = TAKE_PTR(s);
529 if (part_uuid)
530 *part_uuid = p_uuid;
531 if (path)
532 *path = TAKE_PTR(p);
533 if (active)
534 *active = header->attr & LOAD_OPTION_ACTIVE;
535
536 return 0;
537 }
538
539 static void to_utf16(uint16_t *dest, const char *src) {
540 int i;
541
542 for (i = 0; src[i] != '\0'; i++)
543 dest[i] = src[i];
544 dest[i] = '\0';
545 }
546
547 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
548 struct guid uuid = {
549 .u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3],
550 .u2 = id.bytes[4] << 8 | id.bytes[5],
551 .u3 = id.bytes[6] << 8 | id.bytes[7],
552 };
553 memcpy(uuid.u4, id.bytes+8, sizeof(uuid.u4));
554 memcpy(guid, &uuid, sizeof(uuid));
555 }
556
557 static uint16_t *tilt_slashes(uint16_t *s) {
558 uint16_t *p;
559
560 for (p = s; *p; p++)
561 if (*p == '/')
562 *p = '\\';
563
564 return s;
565 }
566
567 int efi_add_boot_option(
568 uint16_t id,
569 const char *title,
570 uint32_t part,
571 uint64_t pstart,
572 uint64_t psize,
573 sd_id128_t part_uuid,
574 const char *path) {
575
576 size_t size, title_len, path_len;
577 _cleanup_free_ char *buf = NULL;
578 struct boot_option *option;
579 struct device_path *devicep;
580 char boot_id[9];
581
582 if (!is_efi_boot())
583 return -EOPNOTSUPP;
584
585 title_len = (strlen(title)+1) * 2;
586 path_len = (strlen(path)+1) * 2;
587
588 buf = malloc0(offsetof(struct boot_option, title) + title_len +
589 sizeof(struct drive_path) +
590 sizeof(struct device_path) + path_len);
591 if (!buf)
592 return -ENOMEM;
593
594 /* header */
595 option = (struct boot_option *)buf;
596 option->attr = LOAD_OPTION_ACTIVE;
597 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
598 offsetof(struct device_path, path) + path_len +
599 offsetof(struct device_path, path);
600 to_utf16(option->title, title);
601 size = offsetof(struct boot_option, title) + title_len;
602
603 /* partition info */
604 devicep = (struct device_path *)(buf + size);
605 devicep->type = MEDIA_DEVICE_PATH;
606 devicep->sub_type = MEDIA_HARDDRIVE_DP;
607 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
608 memcpy(&devicep->drive.part_nr, &part, sizeof(uint32_t));
609 memcpy(&devicep->drive.part_start, &pstart, sizeof(uint64_t));
610 memcpy(&devicep->drive.part_size, &psize, sizeof(uint64_t));
611 id128_to_efi_guid(part_uuid, devicep->drive.signature);
612 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
613 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
614 size += devicep->length;
615
616 /* path to loader */
617 devicep = (struct device_path *)(buf + size);
618 devicep->type = MEDIA_DEVICE_PATH;
619 devicep->sub_type = MEDIA_FILEPATH_DP;
620 devicep->length = offsetof(struct device_path, path) + path_len;
621 to_utf16(devicep->path, path);
622 tilt_slashes(devicep->path);
623 size += devicep->length;
624
625 /* end of path */
626 devicep = (struct device_path *)(buf + size);
627 devicep->type = END_DEVICE_PATH_TYPE;
628 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
629 devicep->length = offsetof(struct device_path, path);
630 size += devicep->length;
631
632 xsprintf(boot_id, "Boot%04X", id);
633 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
634 }
635
636 int efi_remove_boot_option(uint16_t id) {
637 char boot_id[9];
638
639 if (!is_efi_boot())
640 return -EOPNOTSUPP;
641
642 xsprintf(boot_id, "Boot%04X", id);
643 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
644 }
645
646 int efi_get_boot_order(uint16_t **order) {
647 _cleanup_free_ void *buf = NULL;
648 size_t l;
649 int r;
650
651 if (!is_efi_boot())
652 return -EOPNOTSUPP;
653
654 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
655 if (r < 0)
656 return r;
657
658 if (l <= 0)
659 return -ENOENT;
660
661 if (l % sizeof(uint16_t) > 0 ||
662 l / sizeof(uint16_t) > INT_MAX)
663 return -EINVAL;
664
665 *order = TAKE_PTR(buf);
666 return (int) (l / sizeof(uint16_t));
667 }
668
669 int efi_set_boot_order(uint16_t *order, size_t n) {
670
671 if (!is_efi_boot())
672 return -EOPNOTSUPP;
673
674 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
675 }
676
677 static int boot_id_hex(const char s[static 4]) {
678 int id = 0, i;
679
680 assert(s);
681
682 for (i = 0; i < 4; i++)
683 if (s[i] >= '0' && s[i] <= '9')
684 id |= (s[i] - '0') << (3 - i) * 4;
685 else if (s[i] >= 'A' && s[i] <= 'F')
686 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
687 else
688 return -EINVAL;
689
690 return id;
691 }
692
693 static int cmp_uint16(const uint16_t *a, const uint16_t *b) {
694 return CMP(*a, *b);
695 }
696
697 int efi_get_boot_options(uint16_t **options) {
698 _cleanup_closedir_ DIR *dir = NULL;
699 _cleanup_free_ uint16_t *list = NULL;
700 struct dirent *de;
701 size_t alloc = 0;
702 int count = 0;
703
704 assert(options);
705
706 if (!is_efi_boot())
707 return -EOPNOTSUPP;
708
709 dir = opendir("/sys/firmware/efi/efivars/");
710 if (!dir)
711 return -errno;
712
713 FOREACH_DIRENT(de, dir, return -errno) {
714 int id;
715
716 if (strncmp(de->d_name, "Boot", 4) != 0)
717 continue;
718
719 if (strlen(de->d_name) != 45)
720 continue;
721
722 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
723 continue;
724
725 id = boot_id_hex(de->d_name + 4);
726 if (id < 0)
727 continue;
728
729 if (!GREEDY_REALLOC(list, alloc, count + 1))
730 return -ENOMEM;
731
732 list[count++] = id;
733 }
734
735 typesafe_qsort(list, count, cmp_uint16);
736
737 *options = TAKE_PTR(list);
738
739 return count;
740 }
741
742 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
743 _cleanup_free_ char *j = NULL;
744 int r;
745 uint64_t x = 0;
746
747 assert(name);
748 assert(u);
749
750 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
751 if (r < 0)
752 return r;
753
754 r = safe_atou64(j, &x);
755 if (r < 0)
756 return r;
757
758 *u = x;
759 return 0;
760 }
761
762 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
763 uint64_t x, y;
764 int r;
765
766 assert(firmware);
767 assert(loader);
768
769 if (!is_efi_boot())
770 return -EOPNOTSUPP;
771
772 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
773 if (r < 0)
774 return r;
775
776 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
777 if (r < 0)
778 return r;
779
780 if (y == 0 || y < x)
781 return -EIO;
782
783 if (y > USEC_PER_HOUR)
784 return -EIO;
785
786 *firmware = x;
787 *loader = y;
788
789 return 0;
790 }
791
792 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
793 _cleanup_free_ char *p = NULL;
794 int r, parsed[16];
795
796 if (!is_efi_boot())
797 return -EOPNOTSUPP;
798
799 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
800 if (r < 0)
801 return r;
802
803 if (sscanf(p, SD_ID128_UUID_FORMAT_STR,
804 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
805 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
806 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
807 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
808 return -EIO;
809
810 if (u) {
811 unsigned i;
812
813 for (i = 0; i < ELEMENTSOF(parsed); i++)
814 u->bytes[i] = parsed[i];
815 }
816
817 return 0;
818 }
819
820 int efi_loader_get_entries(char ***ret) {
821 _cleanup_free_ char16_t *entries = NULL;
822 _cleanup_strv_free_ char **l = NULL;
823 size_t size, i, start;
824 int r;
825
826 assert(ret);
827
828 if (!is_efi_boot())
829 return -EOPNOTSUPP;
830
831 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderEntries", NULL, (void**) &entries, &size);
832 if (r < 0)
833 return r;
834
835 /* The variable contains a series of individually NUL terminated UTF-16 strings. */
836
837 for (i = 0, start = 0;; i++) {
838 _cleanup_free_ char *decoded = NULL;
839 bool end;
840
841 /* Is this the end of the variable's data? */
842 end = i * sizeof(char16_t) >= size;
843
844 /* Are we in the middle of a string? (i.e. not at the end of the variable, nor at a NUL terminator?) If
845 * so, let's go to the next entry. */
846 if (!end && entries[i] != 0)
847 continue;
848
849 /* We reached the end of a string, let's decode it into UTF-8 */
850 decoded = utf16_to_utf8(entries + start, (i - start) * sizeof(char16_t));
851 if (!decoded)
852 return -ENOMEM;
853
854 if (efi_loader_entry_name_valid(decoded)) {
855 r = strv_consume(&l, TAKE_PTR(decoded));
856 if (r < 0)
857 return r;
858 } else
859 log_debug("Ignoring invalid loader entry '%s'.", decoded);
860
861 /* We reached the end of the variable */
862 if (end)
863 break;
864
865 /* Continue after the NUL byte */
866 start = i + 1;
867 }
868
869 *ret = TAKE_PTR(l);
870 return 0;
871 }
872
873 int efi_loader_get_features(uint64_t *ret) {
874 _cleanup_free_ void *v = NULL;
875 size_t s;
876 int r;
877
878 if (!is_efi_boot()) {
879 *ret = 0;
880 return 0;
881 }
882
883 r = efi_get_variable(EFI_VENDOR_LOADER, "LoaderFeatures", NULL, &v, &s);
884 if (r == -ENOENT) {
885 _cleanup_free_ char *info = NULL;
886
887 /* The new (v240+) LoaderFeatures variable is not supported, let's see if it's systemd-boot at all */
888 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderInfo", &info);
889 if (r < 0) {
890 if (r != -ENOENT)
891 return r;
892
893 /* Variable not set, definitely means not systemd-boot */
894
895 } else if (first_word(info, "systemd-boot")) {
896
897 /* An older systemd-boot version. Let's hardcode the feature set, since it was pretty
898 * static in all its versions. */
899
900 *ret = EFI_LOADER_FEATURE_CONFIG_TIMEOUT |
901 EFI_LOADER_FEATURE_ENTRY_DEFAULT |
902 EFI_LOADER_FEATURE_ENTRY_ONESHOT;
903
904 return 0;
905 }
906
907 /* No features supported */
908 *ret = 0;
909 return 0;
910 }
911 if (r < 0)
912 return r;
913
914 if (s != sizeof(uint64_t))
915 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
916 "LoaderFeatures EFI variable doesn't have the right size.");
917
918 memcpy(ret, v, sizeof(uint64_t));
919 return 0;
920 }
921
922 #endif
923
924 bool efi_loader_entry_name_valid(const char *s) {
925 if (isempty(s))
926 return false;
927
928 if (strlen(s) > FILENAME_MAX) /* Make sure entry names fit in filenames */
929 return false;
930
931 return in_charset(s, ALPHANUMERICAL "+-_.");
932 }
933
934 char *efi_tilt_backslashes(char *s) {
935 char *p;
936
937 for (p = s; *p; p++)
938 if (*p == '\\')
939 *p = '/';
940
941 return s;
942 }