]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efivars.c
efivars: minor coding style improvements
[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 _cleanup_free_ void *v = NULL;
89 uint8_t b;
90 size_t s;
91 int r;
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 return b > 0;
102 }
103
104 bool is_efi_secure_boot(void) {
105 return read_flag("SecureBoot") > 0;
106 }
107
108 bool is_efi_secure_boot_setup_mode(void) {
109 return read_flag("SetupMode") > 0;
110 }
111
112 int efi_reboot_to_firmware_supported(void) {
113 _cleanup_free_ void *v = NULL;
114 uint64_t b;
115 size_t s;
116 int r;
117
118 if (!is_efi_boot() || detect_container() > 0)
119 return -EOPNOTSUPP;
120
121 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
122 if (r < 0)
123 return r;
124 if (s != sizeof(uint64_t))
125 return -EINVAL;
126
127 b = *(uint64_t*) v;
128 if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
129 return -EOPNOTSUPP; /* bit unset? it's not supported then */
130
131 return 0;
132 }
133
134 static int get_os_indications(uint64_t *os_indication) {
135 _cleanup_free_ void *v = NULL;
136 size_t s;
137 int r;
138
139 r = efi_reboot_to_firmware_supported();
140 if (r < 0)
141 return r;
142
143 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
144 if (r == -ENOENT) {
145 /* Some firmware implementations that do support
146 * OsIndications and report that with
147 * OsIndicationsSupported will remove the
148 * OsIndications variable when it is unset. Let's
149 * pretend it's 0 then, to hide this implementation
150 * detail. Note that this call will return -ENOENT
151 * then only if the support for OsIndications is
152 * missing entirely, as determined by
153 * efi_reboot_to_firmware_supported() 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 int efi_get_variable(
197 sd_id128_t vendor,
198 const char *name,
199 uint32_t *attribute,
200 void **value,
201 size_t *size) {
202
203 _cleanup_close_ int fd = -1;
204 _cleanup_free_ char *p = NULL;
205 uint32_t a;
206 ssize_t n;
207 struct stat st;
208 _cleanup_free_ void *buf = NULL;
209
210 assert(name);
211 assert(value);
212 assert(size);
213
214 if (asprintf(&p,
215 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
216 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
217 return -ENOMEM;
218
219 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
220 if (fd < 0)
221 return -errno;
222
223 if (fstat(fd, &st) < 0)
224 return -errno;
225 if (st.st_size < 4)
226 return -EIO;
227 if (st.st_size > 4*1024*1024 + 4)
228 return -E2BIG;
229
230 n = read(fd, &a, sizeof(a));
231 if (n < 0)
232 return -errno;
233 if (n != sizeof(a))
234 return -EIO;
235
236 buf = malloc(st.st_size - 4 + 2);
237 if (!buf)
238 return -ENOMEM;
239
240 n = read(fd, buf, (size_t) st.st_size - 4);
241 if (n < 0)
242 return -errno;
243 if (n != (ssize_t) st.st_size - 4)
244 return -EIO;
245
246 /* Always NUL terminate (2 bytes, to protect UTF-16) */
247 ((char*) buf)[st.st_size - 4] = 0;
248 ((char*) buf)[st.st_size - 4 + 1] = 0;
249
250 *value = buf;
251 buf = NULL;
252 *size = (size_t) st.st_size - 4;
253
254 if (attribute)
255 *attribute = a;
256
257 return 0;
258 }
259
260 int efi_set_variable(
261 sd_id128_t vendor,
262 const char *name,
263 const void *value,
264 size_t size) {
265
266 struct var {
267 uint32_t attr;
268 char buf[];
269 } _packed_ * _cleanup_free_ buf = NULL;
270 _cleanup_free_ char *p = NULL;
271 _cleanup_close_ int fd = -1;
272
273 assert(name);
274 assert(value || size == 0);
275
276 if (asprintf(&p,
277 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
278 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
279 return -ENOMEM;
280
281 if (size == 0) {
282 if (unlink(p) < 0)
283 return -errno;
284 return 0;
285 }
286
287 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
288 if (fd < 0)
289 return -errno;
290
291 buf = malloc(sizeof(uint32_t) + size);
292 if (!buf)
293 return -ENOMEM;
294
295 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
296 memcpy(buf->buf, value, size);
297
298 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
299 }
300
301 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
302 _cleanup_free_ void *s = NULL;
303 size_t ss = 0;
304 int r;
305 char *x;
306
307 r = efi_get_variable(vendor, name, NULL, &s, &ss);
308 if (r < 0)
309 return r;
310
311 x = utf16_to_utf8(s, ss);
312 if (!x)
313 return -ENOMEM;
314
315 *p = x;
316 return 0;
317 }
318
319 static size_t utf16_size(const uint16_t *s) {
320 size_t l = 0;
321
322 while (s[l] > 0)
323 l++;
324
325 return (l+1) * sizeof(uint16_t);
326 }
327
328 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
329 struct uuid {
330 uint32_t u1;
331 uint16_t u2;
332 uint16_t u3;
333 uint8_t u4[8];
334 } _packed_;
335 const struct uuid *uuid = guid;
336
337 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
338 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
339 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
340 id128->bytes[3] = (uuid->u1) & 0xff;
341 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
342 id128->bytes[5] = (uuid->u2) & 0xff;
343 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
344 id128->bytes[7] = (uuid->u3) & 0xff;
345 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
346 }
347
348 int efi_get_boot_option(
349 uint16_t id,
350 char **title,
351 sd_id128_t *part_uuid,
352 char **path,
353 bool *active) {
354
355 char boot_id[9];
356 _cleanup_free_ uint8_t *buf = NULL;
357 size_t l;
358 struct boot_option *header;
359 size_t title_size;
360 _cleanup_free_ char *s = NULL, *p = NULL;
361 sd_id128_t p_uuid = SD_ID128_NULL;
362 int r;
363
364 xsprintf(boot_id, "Boot%04X", id);
365 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
366 if (r < 0)
367 return r;
368 if (l < sizeof(struct boot_option))
369 return -ENOENT;
370
371 header = (struct boot_option *)buf;
372 title_size = utf16_size(header->title);
373 if (title_size > l - offsetof(struct boot_option, title))
374 return -EINVAL;
375
376 if (title) {
377 s = utf16_to_utf8(header->title, title_size);
378 if (!s)
379 return -ENOMEM;
380 }
381
382 if (header->path_len > 0) {
383 uint8_t *dbuf;
384 size_t dnext;
385
386 dbuf = buf + offsetof(struct boot_option, title) + title_size;
387 dnext = 0;
388 while (dnext < header->path_len) {
389 struct device_path *dpath;
390
391 dpath = (struct device_path *)(dbuf + dnext);
392 if (dpath->length < 4)
393 break;
394
395 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
396 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
397 break;
398
399 dnext += dpath->length;
400
401 /* Type 0x04 – Media Device Path */
402 if (dpath->type != MEDIA_DEVICE_PATH)
403 continue;
404
405 /* Sub-Type 1 – Hard Drive */
406 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
407 /* 0x02 – GUID Partition Table */
408 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
409 continue;
410
411 /* 0x02 – GUID signature */
412 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
413 continue;
414
415 if (part_uuid)
416 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
417 continue;
418 }
419
420 /* Sub-Type 4 – File Path */
421 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
422 p = utf16_to_utf8(dpath->path, dpath->length-4);
423 efi_tilt_backslashes(p);
424 continue;
425 }
426 }
427 }
428
429 if (title) {
430 *title = s;
431 s = NULL;
432 }
433 if (part_uuid)
434 *part_uuid = p_uuid;
435 if (path) {
436 *path = p;
437 p = NULL;
438 }
439 if (active)
440 *active = !!(header->attr & LOAD_OPTION_ACTIVE);
441
442 return 0;
443 }
444
445 static void to_utf16(uint16_t *dest, const char *src) {
446 int i;
447
448 for (i = 0; src[i] != '\0'; i++)
449 dest[i] = src[i];
450 dest[i] = '\0';
451 }
452
453 struct guid {
454 uint32_t u1;
455 uint16_t u2;
456 uint16_t u3;
457 uint8_t u4[8];
458 } _packed_;
459
460 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
461 struct guid *uuid = guid;
462
463 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
464 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
465 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
466 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
467 }
468
469 static uint16_t *tilt_slashes(uint16_t *s) {
470 uint16_t *p;
471
472 for (p = s; *p; p++)
473 if (*p == '/')
474 *p = '\\';
475
476 return s;
477 }
478
479 int efi_add_boot_option(uint16_t id, const char *title,
480 uint32_t part, uint64_t pstart, uint64_t psize,
481 sd_id128_t part_uuid, const char *path) {
482 char boot_id[9];
483 size_t size;
484 size_t title_len;
485 size_t path_len;
486 struct boot_option *option;
487 struct device_path *devicep;
488 _cleanup_free_ char *buf = NULL;
489
490 title_len = (strlen(title)+1) * 2;
491 path_len = (strlen(path)+1) * 2;
492
493 buf = calloc(sizeof(struct boot_option) + title_len +
494 sizeof(struct drive_path) +
495 sizeof(struct device_path) + path_len, 1);
496 if (!buf)
497 return -ENOMEM;
498
499 /* header */
500 option = (struct boot_option *)buf;
501 option->attr = LOAD_OPTION_ACTIVE;
502 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
503 offsetof(struct device_path, path) + path_len +
504 offsetof(struct device_path, path);
505 to_utf16(option->title, title);
506 size = offsetof(struct boot_option, title) + title_len;
507
508 /* partition info */
509 devicep = (struct device_path *)(buf + size);
510 devicep->type = MEDIA_DEVICE_PATH;
511 devicep->sub_type = MEDIA_HARDDRIVE_DP;
512 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
513 devicep->drive.part_nr = part;
514 devicep->drive.part_start = pstart;
515 devicep->drive.part_size = psize;
516 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
517 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
518 id128_to_efi_guid(part_uuid, devicep->drive.signature);
519 size += devicep->length;
520
521 /* path to loader */
522 devicep = (struct device_path *)(buf + size);
523 devicep->type = MEDIA_DEVICE_PATH;
524 devicep->sub_type = MEDIA_FILEPATH_DP;
525 devicep->length = offsetof(struct device_path, path) + path_len;
526 to_utf16(devicep->path, path);
527 tilt_slashes(devicep->path);
528 size += devicep->length;
529
530 /* end of path */
531 devicep = (struct device_path *)(buf + size);
532 devicep->type = END_DEVICE_PATH_TYPE;
533 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
534 devicep->length = offsetof(struct device_path, path);
535 size += devicep->length;
536
537 xsprintf(boot_id, "Boot%04X", id);
538 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
539 }
540
541 int efi_remove_boot_option(uint16_t id) {
542 char boot_id[9];
543
544 xsprintf(boot_id, "Boot%04X", id);
545 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
546 }
547
548 int efi_get_boot_order(uint16_t **order) {
549 _cleanup_free_ void *buf = NULL;
550 size_t l;
551 int r;
552
553 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
554 if (r < 0)
555 return r;
556
557 if (l <= 0)
558 return -ENOENT;
559
560 if (l % sizeof(uint16_t) > 0 ||
561 l / sizeof(uint16_t) > INT_MAX)
562 return -EINVAL;
563
564 *order = buf;
565 buf = NULL;
566 return (int) (l / sizeof(uint16_t));
567 }
568
569 int efi_set_boot_order(uint16_t *order, size_t n) {
570 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
571 }
572
573 static int boot_id_hex(const char s[4]) {
574 int i;
575 int id = 0;
576
577 for (i = 0; i < 4; i++)
578 if (s[i] >= '0' && s[i] <= '9')
579 id |= (s[i] - '0') << (3 - i) * 4;
580 else if (s[i] >= 'A' && s[i] <= 'F')
581 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
582 else
583 return -EINVAL;
584
585 return id;
586 }
587
588 static int cmp_uint16(const void *_a, const void *_b) {
589 const uint16_t *a = _a, *b = _b;
590
591 return (int)*a - (int)*b;
592 }
593
594 int efi_get_boot_options(uint16_t **options) {
595 _cleanup_closedir_ DIR *dir = NULL;
596 struct dirent *de;
597 _cleanup_free_ uint16_t *list = NULL;
598 size_t alloc = 0;
599 int count = 0;
600
601 assert(options);
602
603 dir = opendir("/sys/firmware/efi/efivars/");
604 if (!dir)
605 return -errno;
606
607 FOREACH_DIRENT(de, dir, return -errno) {
608 int id;
609
610 if (strncmp(de->d_name, "Boot", 4) != 0)
611 continue;
612
613 if (strlen(de->d_name) != 45)
614 continue;
615
616 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
617 continue;
618
619 id = boot_id_hex(de->d_name + 4);
620 if (id < 0)
621 continue;
622
623 if (!GREEDY_REALLOC(list, alloc, count + 1))
624 return -ENOMEM;
625
626 list[count++] = id;
627 }
628
629 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
630
631 *options = list;
632 list = NULL;
633 return count;
634 }
635
636 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
637 _cleanup_free_ char *j = NULL;
638 int r;
639 uint64_t x = 0;
640
641 assert(name);
642 assert(u);
643
644 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
645 if (r < 0)
646 return r;
647
648 r = safe_atou64(j, &x);
649 if (r < 0)
650 return r;
651
652 *u = x;
653 return 0;
654 }
655
656 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
657 uint64_t x, y;
658 int r;
659
660 assert(firmware);
661 assert(loader);
662
663 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
664 if (r < 0)
665 return r;
666
667 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
668 if (r < 0)
669 return r;
670
671 if (y == 0 || y < x)
672 return -EIO;
673
674 if (y > USEC_PER_HOUR)
675 return -EIO;
676
677 *firmware = x;
678 *loader = y;
679
680 return 0;
681 }
682
683 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
684 _cleanup_free_ char *p = NULL;
685 int r, parsed[16];
686
687 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
688 if (r < 0)
689 return r;
690
691 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
692 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
693 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
694 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
695 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
696 return -EIO;
697
698 if (u) {
699 unsigned i;
700
701 for (i = 0; i < ELEMENTSOF(parsed); i++)
702 u->bytes[i] = parsed[i];
703 }
704
705 return 0;
706 }
707
708 #endif
709
710 char *efi_tilt_backslashes(char *s) {
711 char *p;
712
713 for (p = s; *p; p++)
714 if (*p == '\\')
715 *p = '/';
716
717 return s;
718 }