]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efivars.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / shared / efivars.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30
31 #include "sd-id128.h"
32
33 #include "alloc-util.h"
34 #include "dirent-util.h"
35 #include "efivars.h"
36 #include "fd-util.h"
37 #include "io-util.h"
38 #include "macro.h"
39 #include "parse-util.h"
40 #include "stdio-util.h"
41 #include "time-util.h"
42 #include "utf8.h"
43 #include "util.h"
44 #include "virt.h"
45
46 #if ENABLE_EFI
47
48 #define LOAD_OPTION_ACTIVE 0x00000001
49 #define MEDIA_DEVICE_PATH 0x04
50 #define MEDIA_HARDDRIVE_DP 0x01
51 #define MEDIA_FILEPATH_DP 0x04
52 #define SIGNATURE_TYPE_GUID 0x02
53 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
54 #define END_DEVICE_PATH_TYPE 0x7f
55 #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff
56 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001
57
58 struct boot_option {
59 uint32_t attr;
60 uint16_t path_len;
61 uint16_t title[];
62 } _packed_;
63
64 struct drive_path {
65 uint32_t part_nr;
66 uint64_t part_start;
67 uint64_t part_size;
68 char signature[16];
69 uint8_t mbr_type;
70 uint8_t signature_type;
71 } _packed_;
72
73 struct device_path {
74 uint8_t type;
75 uint8_t sub_type;
76 uint16_t length;
77 union {
78 uint16_t path[0];
79 struct drive_path drive;
80 };
81 } _packed_;
82
83 bool is_efi_boot(void) {
84 return access("/sys/firmware/efi", F_OK) >= 0;
85 }
86
87 static int read_flag(const char *varname) {
88 int r;
89 _cleanup_free_ void *v = NULL;
90 size_t s;
91 uint8_t b;
92
93 r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
94 if (r < 0)
95 return r;
96
97 if (s != 1)
98 return -EINVAL;
99
100 b = *(uint8_t *)v;
101 r = b > 0;
102 return r;
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 int r;
115 size_t s;
116 uint64_t b;
117 _cleanup_free_ void *v = NULL;
118
119 if (!is_efi_boot() || detect_container() > 0)
120 return -EOPNOTSUPP;
121
122 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
123 if (r < 0)
124 return r;
125 else if (s != sizeof(uint64_t))
126 return -EINVAL;
127
128 b = *(uint64_t *)v;
129 b &= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
130 return b > 0 ? 0 : -EOPNOTSUPP;
131 }
132
133 static int get_os_indications(uint64_t *os_indication) {
134 int r;
135 size_t s;
136 _cleanup_free_ void *v = NULL;
137
138 r = efi_reboot_to_firmware_supported();
139 if (r < 0)
140 return r;
141
142 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
143 if (r == -ENOENT) {
144 /* Some firmware implementations that do support
145 * OsIndications and report that with
146 * OsIndicationsSupported will remove the
147 * OsIndications variable when it is unset. Let's
148 * pretend it's 0 then, to hide this implementation
149 * detail. Note that this call will return -ENOENT
150 * then only if the support for OsIndications is
151 * missing entirely, as determined by
152 * efi_reboot_to_firmware_supported() above. */
153 *os_indication = 0;
154 return 0;
155 } else if (r < 0)
156 return r;
157 else if (s != sizeof(uint64_t))
158 return -EINVAL;
159
160 *os_indication = *(uint64_t *)v;
161 return 0;
162 }
163
164 int efi_get_reboot_to_firmware(void) {
165 int r;
166 uint64_t b;
167
168 r = get_os_indications(&b);
169 if (r < 0)
170 return r;
171
172 return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
173 }
174
175 int efi_set_reboot_to_firmware(bool value) {
176 int r;
177 uint64_t b, b_new;
178
179 r = get_os_indications(&b);
180 if (r < 0)
181 return r;
182
183 if (value)
184 b_new = b | EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
185 else
186 b_new = b & ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
187
188 /* Avoid writing to efi vars store if we can due to firmware bugs. */
189 if (b != b_new)
190 return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t));
191
192 return 0;
193 }
194
195 int efi_get_variable(
196 sd_id128_t vendor,
197 const char *name,
198 uint32_t *attribute,
199 void **value,
200 size_t *size) {
201
202 _cleanup_close_ int fd = -1;
203 _cleanup_free_ char *p = NULL;
204 uint32_t a;
205 ssize_t n;
206 struct stat st;
207 _cleanup_free_ void *buf = NULL;
208
209 assert(name);
210 assert(value);
211 assert(size);
212
213 if (asprintf(&p,
214 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
215 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
216 return -ENOMEM;
217
218 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
219 if (fd < 0)
220 return -errno;
221
222 if (fstat(fd, &st) < 0)
223 return -errno;
224 if (st.st_size < 4)
225 return -EIO;
226 if (st.st_size > 4*1024*1024 + 4)
227 return -E2BIG;
228
229 n = read(fd, &a, sizeof(a));
230 if (n < 0)
231 return -errno;
232 if (n != sizeof(a))
233 return -EIO;
234
235 buf = malloc(st.st_size - 4 + 2);
236 if (!buf)
237 return -ENOMEM;
238
239 n = read(fd, buf, (size_t) st.st_size - 4);
240 if (n < 0)
241 return -errno;
242 if (n != (ssize_t) st.st_size - 4)
243 return -EIO;
244
245 /* Always NUL terminate (2 bytes, to protect UTF-16) */
246 ((char*) buf)[st.st_size - 4] = 0;
247 ((char*) buf)[st.st_size - 4 + 1] = 0;
248
249 *value = buf;
250 buf = NULL;
251 *size = (size_t) st.st_size - 4;
252
253 if (attribute)
254 *attribute = a;
255
256 return 0;
257 }
258
259 int efi_set_variable(
260 sd_id128_t vendor,
261 const char *name,
262 const void *value,
263 size_t size) {
264
265 struct var {
266 uint32_t attr;
267 char buf[];
268 } _packed_ * _cleanup_free_ buf = NULL;
269 _cleanup_free_ char *p = NULL;
270 _cleanup_close_ int fd = -1;
271
272 assert(name);
273 assert(value || size == 0);
274
275 if (asprintf(&p,
276 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
277 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
278 return -ENOMEM;
279
280 if (size == 0) {
281 if (unlink(p) < 0)
282 return -errno;
283 return 0;
284 }
285
286 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
287 if (fd < 0)
288 return -errno;
289
290 buf = malloc(sizeof(uint32_t) + size);
291 if (!buf)
292 return -ENOMEM;
293
294 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
295 memcpy(buf->buf, value, size);
296
297 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
298 }
299
300 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
301 _cleanup_free_ void *s = NULL;
302 size_t ss = 0;
303 int r;
304 char *x;
305
306 r = efi_get_variable(vendor, name, NULL, &s, &ss);
307 if (r < 0)
308 return r;
309
310 x = utf16_to_utf8(s, ss);
311 if (!x)
312 return -ENOMEM;
313
314 *p = x;
315 return 0;
316 }
317
318 static size_t utf16_size(const uint16_t *s) {
319 size_t l = 0;
320
321 while (s[l] > 0)
322 l++;
323
324 return (l+1) * sizeof(uint16_t);
325 }
326
327 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
328 struct uuid {
329 uint32_t u1;
330 uint16_t u2;
331 uint16_t u3;
332 uint8_t u4[8];
333 } _packed_;
334 const struct uuid *uuid = guid;
335
336 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
337 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
338 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
339 id128->bytes[3] = (uuid->u1) & 0xff;
340 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
341 id128->bytes[5] = (uuid->u2) & 0xff;
342 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
343 id128->bytes[7] = (uuid->u3) & 0xff;
344 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
345 }
346
347 int efi_get_boot_option(
348 uint16_t id,
349 char **title,
350 sd_id128_t *part_uuid,
351 char **path,
352 bool *active) {
353
354 char boot_id[9];
355 _cleanup_free_ uint8_t *buf = NULL;
356 size_t l;
357 struct boot_option *header;
358 size_t title_size;
359 _cleanup_free_ char *s = NULL, *p = NULL;
360 sd_id128_t p_uuid = SD_ID128_NULL;
361 int r;
362
363 xsprintf(boot_id, "Boot%04X", id);
364 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
365 if (r < 0)
366 return r;
367 if (l < sizeof(struct boot_option))
368 return -ENOENT;
369
370 header = (struct boot_option *)buf;
371 title_size = utf16_size(header->title);
372 if (title_size > l - offsetof(struct boot_option, title))
373 return -EINVAL;
374
375 if (title) {
376 s = utf16_to_utf8(header->title, title_size);
377 if (!s)
378 return -ENOMEM;
379 }
380
381 if (header->path_len > 0) {
382 uint8_t *dbuf;
383 size_t dnext;
384
385 dbuf = buf + offsetof(struct boot_option, title) + title_size;
386 dnext = 0;
387 while (dnext < header->path_len) {
388 struct device_path *dpath;
389
390 dpath = (struct device_path *)(dbuf + dnext);
391 if (dpath->length < 4)
392 break;
393
394 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
395 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
396 break;
397
398 dnext += dpath->length;
399
400 /* Type 0x04 – Media Device Path */
401 if (dpath->type != MEDIA_DEVICE_PATH)
402 continue;
403
404 /* Sub-Type 1 – Hard Drive */
405 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
406 /* 0x02 – GUID Partition Table */
407 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
408 continue;
409
410 /* 0x02 – GUID signature */
411 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
412 continue;
413
414 if (part_uuid)
415 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
416 continue;
417 }
418
419 /* Sub-Type 4 – File Path */
420 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
421 p = utf16_to_utf8(dpath->path, dpath->length-4);
422 efi_tilt_backslashes(p);
423 continue;
424 }
425 }
426 }
427
428 if (title) {
429 *title = s;
430 s = NULL;
431 }
432 if (part_uuid)
433 *part_uuid = p_uuid;
434 if (path) {
435 *path = p;
436 p = NULL;
437 }
438 if (active)
439 *active = !!(header->attr & LOAD_OPTION_ACTIVE);
440
441 return 0;
442 }
443
444 static void to_utf16(uint16_t *dest, const char *src) {
445 int i;
446
447 for (i = 0; src[i] != '\0'; i++)
448 dest[i] = src[i];
449 dest[i] = '\0';
450 }
451
452 struct guid {
453 uint32_t u1;
454 uint16_t u2;
455 uint16_t u3;
456 uint8_t u4[8];
457 } _packed_;
458
459 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
460 struct guid *uuid = guid;
461
462 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
463 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
464 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
465 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
466 }
467
468 static uint16_t *tilt_slashes(uint16_t *s) {
469 uint16_t *p;
470
471 for (p = s; *p; p++)
472 if (*p == '/')
473 *p = '\\';
474
475 return s;
476 }
477
478 int efi_add_boot_option(uint16_t id, const char *title,
479 uint32_t part, uint64_t pstart, uint64_t psize,
480 sd_id128_t part_uuid, const char *path) {
481 char boot_id[9];
482 size_t size;
483 size_t title_len;
484 size_t path_len;
485 struct boot_option *option;
486 struct device_path *devicep;
487 _cleanup_free_ char *buf = NULL;
488
489 title_len = (strlen(title)+1) * 2;
490 path_len = (strlen(path)+1) * 2;
491
492 buf = calloc(sizeof(struct boot_option) + title_len +
493 sizeof(struct drive_path) +
494 sizeof(struct device_path) + path_len, 1);
495 if (!buf)
496 return -ENOMEM;
497
498 /* header */
499 option = (struct boot_option *)buf;
500 option->attr = LOAD_OPTION_ACTIVE;
501 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
502 offsetof(struct device_path, path) + path_len +
503 offsetof(struct device_path, path);
504 to_utf16(option->title, title);
505 size = offsetof(struct boot_option, title) + title_len;
506
507 /* partition info */
508 devicep = (struct device_path *)(buf + size);
509 devicep->type = MEDIA_DEVICE_PATH;
510 devicep->sub_type = MEDIA_HARDDRIVE_DP;
511 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
512 devicep->drive.part_nr = part;
513 devicep->drive.part_start = pstart;
514 devicep->drive.part_size = psize;
515 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
516 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
517 id128_to_efi_guid(part_uuid, devicep->drive.signature);
518 size += devicep->length;
519
520 /* path to loader */
521 devicep = (struct device_path *)(buf + size);
522 devicep->type = MEDIA_DEVICE_PATH;
523 devicep->sub_type = MEDIA_FILEPATH_DP;
524 devicep->length = offsetof(struct device_path, path) + path_len;
525 to_utf16(devicep->path, path);
526 tilt_slashes(devicep->path);
527 size += devicep->length;
528
529 /* end of path */
530 devicep = (struct device_path *)(buf + size);
531 devicep->type = END_DEVICE_PATH_TYPE;
532 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
533 devicep->length = offsetof(struct device_path, path);
534 size += devicep->length;
535
536 xsprintf(boot_id, "Boot%04X", id);
537 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
538 }
539
540 int efi_remove_boot_option(uint16_t id) {
541 char boot_id[9];
542
543 xsprintf(boot_id, "Boot%04X", id);
544 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
545 }
546
547 int efi_get_boot_order(uint16_t **order) {
548 _cleanup_free_ void *buf = NULL;
549 size_t l;
550 int r;
551
552 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
553 if (r < 0)
554 return r;
555
556 if (l <= 0)
557 return -ENOENT;
558
559 if (l % sizeof(uint16_t) > 0 ||
560 l / sizeof(uint16_t) > INT_MAX)
561 return -EINVAL;
562
563 *order = buf;
564 buf = NULL;
565 return (int) (l / sizeof(uint16_t));
566 }
567
568 int efi_set_boot_order(uint16_t *order, size_t n) {
569 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
570 }
571
572 static int boot_id_hex(const char s[4]) {
573 int i;
574 int id = 0;
575
576 for (i = 0; i < 4; i++)
577 if (s[i] >= '0' && s[i] <= '9')
578 id |= (s[i] - '0') << (3 - i) * 4;
579 else if (s[i] >= 'A' && s[i] <= 'F')
580 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
581 else
582 return -EINVAL;
583
584 return id;
585 }
586
587 static int cmp_uint16(const void *_a, const void *_b) {
588 const uint16_t *a = _a, *b = _b;
589
590 return (int)*a - (int)*b;
591 }
592
593 int efi_get_boot_options(uint16_t **options) {
594 _cleanup_closedir_ DIR *dir = NULL;
595 struct dirent *de;
596 _cleanup_free_ uint16_t *list = NULL;
597 size_t alloc = 0;
598 int count = 0;
599
600 assert(options);
601
602 dir = opendir("/sys/firmware/efi/efivars/");
603 if (!dir)
604 return -errno;
605
606 FOREACH_DIRENT(de, dir, return -errno) {
607 int id;
608
609 if (strncmp(de->d_name, "Boot", 4) != 0)
610 continue;
611
612 if (strlen(de->d_name) != 45)
613 continue;
614
615 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
616 continue;
617
618 id = boot_id_hex(de->d_name + 4);
619 if (id < 0)
620 continue;
621
622 if (!GREEDY_REALLOC(list, alloc, count + 1))
623 return -ENOMEM;
624
625 list[count++] = id;
626 }
627
628 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
629
630 *options = list;
631 list = NULL;
632 return count;
633 }
634
635 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
636 _cleanup_free_ char *j = NULL;
637 int r;
638 uint64_t x = 0;
639
640 assert(name);
641 assert(u);
642
643 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
644 if (r < 0)
645 return r;
646
647 r = safe_atou64(j, &x);
648 if (r < 0)
649 return r;
650
651 *u = x;
652 return 0;
653 }
654
655 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
656 uint64_t x, y;
657 int r;
658
659 assert(firmware);
660 assert(loader);
661
662 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
663 if (r < 0)
664 return r;
665
666 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
667 if (r < 0)
668 return r;
669
670 if (y == 0 || y < x)
671 return -EIO;
672
673 if (y > USEC_PER_HOUR)
674 return -EIO;
675
676 *firmware = x;
677 *loader = y;
678
679 return 0;
680 }
681
682 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
683 _cleanup_free_ char *p = NULL;
684 int r, parsed[16];
685
686 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
687 if (r < 0)
688 return r;
689
690 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
691 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
692 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
693 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
694 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
695 return -EIO;
696
697 if (u) {
698 unsigned i;
699
700 for (i = 0; i < ELEMENTSOF(parsed); i++)
701 u->bytes[i] = parsed[i];
702 }
703
704 return 0;
705 }
706
707 #endif
708
709 char *efi_tilt_backslashes(char *s) {
710 char *p;
711
712 for (p = s; *p; p++)
713 if (*p == '\\')
714 *p = '/';
715
716 return s;
717 }