]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efivars.c
Merge pull request #8554 from poettering/chase-trail-slash
[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 == -ENOENT) /* variable doesn't exist? it's not supported then */
123 return -EOPNOTSUPP;
124 if (r < 0)
125 return r;
126 if (s != sizeof(uint64_t))
127 return -EINVAL;
128
129 b = *(uint64_t*) v;
130 if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
131 return -EOPNOTSUPP; /* bit unset? it's not supported then */
132
133 return 0;
134 }
135
136 static int get_os_indications(uint64_t *os_indication) {
137 _cleanup_free_ void *v = NULL;
138 size_t s;
139 int r;
140
141 r = efi_reboot_to_firmware_supported();
142 if (r < 0)
143 return r;
144
145 r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndications", NULL, &v, &s);
146 if (r == -ENOENT) {
147 /* Some firmware implementations that do support
148 * OsIndications and report that with
149 * OsIndicationsSupported will remove the
150 * OsIndications variable when it is unset. Let's
151 * pretend it's 0 then, to hide this implementation
152 * detail. Note that this call will return -ENOENT
153 * then only if the support for OsIndications is
154 * missing entirely, as determined by
155 * efi_reboot_to_firmware_supported() above. */
156 *os_indication = 0;
157 return 0;
158 } else if (r < 0)
159 return r;
160 else if (s != sizeof(uint64_t))
161 return -EINVAL;
162
163 *os_indication = *(uint64_t *)v;
164 return 0;
165 }
166
167 int efi_get_reboot_to_firmware(void) {
168 int r;
169 uint64_t b;
170
171 r = get_os_indications(&b);
172 if (r < 0)
173 return r;
174
175 return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
176 }
177
178 int efi_set_reboot_to_firmware(bool value) {
179 int r;
180 uint64_t b, b_new;
181
182 r = get_os_indications(&b);
183 if (r < 0)
184 return r;
185
186 if (value)
187 b_new = b | EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
188 else
189 b_new = b & ~EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
190
191 /* Avoid writing to efi vars store if we can due to firmware bugs. */
192 if (b != b_new)
193 return efi_set_variable(EFI_VENDOR_GLOBAL, "OsIndications", &b_new, sizeof(uint64_t));
194
195 return 0;
196 }
197
198 int efi_get_variable(
199 sd_id128_t vendor,
200 const char *name,
201 uint32_t *attribute,
202 void **value,
203 size_t *size) {
204
205 _cleanup_close_ int fd = -1;
206 _cleanup_free_ char *p = NULL;
207 uint32_t a;
208 ssize_t n;
209 struct stat st;
210 _cleanup_free_ void *buf = NULL;
211
212 assert(name);
213 assert(value);
214 assert(size);
215
216 if (asprintf(&p,
217 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
218 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
219 return -ENOMEM;
220
221 fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
222 if (fd < 0)
223 return -errno;
224
225 if (fstat(fd, &st) < 0)
226 return -errno;
227 if (st.st_size < 4)
228 return -EIO;
229 if (st.st_size > 4*1024*1024 + 4)
230 return -E2BIG;
231
232 n = read(fd, &a, sizeof(a));
233 if (n < 0)
234 return -errno;
235 if (n != sizeof(a))
236 return -EIO;
237
238 buf = malloc(st.st_size - 4 + 2);
239 if (!buf)
240 return -ENOMEM;
241
242 n = read(fd, buf, (size_t) st.st_size - 4);
243 if (n < 0)
244 return -errno;
245 if (n != (ssize_t) st.st_size - 4)
246 return -EIO;
247
248 /* Always NUL terminate (2 bytes, to protect UTF-16) */
249 ((char*) buf)[st.st_size - 4] = 0;
250 ((char*) buf)[st.st_size - 4 + 1] = 0;
251
252 *value = TAKE_PTR(buf);
253 *size = (size_t) st.st_size - 4;
254
255 if (attribute)
256 *attribute = a;
257
258 return 0;
259 }
260
261 int efi_set_variable(
262 sd_id128_t vendor,
263 const char *name,
264 const void *value,
265 size_t size) {
266
267 struct var {
268 uint32_t attr;
269 char buf[];
270 } _packed_ * _cleanup_free_ buf = NULL;
271 _cleanup_free_ char *p = NULL;
272 _cleanup_close_ int fd = -1;
273
274 assert(name);
275 assert(value || size == 0);
276
277 if (asprintf(&p,
278 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
279 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
280 return -ENOMEM;
281
282 if (size == 0) {
283 if (unlink(p) < 0)
284 return -errno;
285 return 0;
286 }
287
288 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
289 if (fd < 0)
290 return -errno;
291
292 buf = malloc(sizeof(uint32_t) + size);
293 if (!buf)
294 return -ENOMEM;
295
296 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
297 memcpy(buf->buf, value, size);
298
299 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
300 }
301
302 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
303 _cleanup_free_ void *s = NULL;
304 size_t ss = 0;
305 int r;
306 char *x;
307
308 r = efi_get_variable(vendor, name, NULL, &s, &ss);
309 if (r < 0)
310 return r;
311
312 x = utf16_to_utf8(s, ss);
313 if (!x)
314 return -ENOMEM;
315
316 *p = x;
317 return 0;
318 }
319
320 static size_t utf16_size(const uint16_t *s) {
321 size_t l = 0;
322
323 while (s[l] > 0)
324 l++;
325
326 return (l+1) * sizeof(uint16_t);
327 }
328
329 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
330 struct uuid {
331 uint32_t u1;
332 uint16_t u2;
333 uint16_t u3;
334 uint8_t u4[8];
335 } _packed_;
336 const struct uuid *uuid = guid;
337
338 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
339 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
340 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
341 id128->bytes[3] = (uuid->u1) & 0xff;
342 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
343 id128->bytes[5] = (uuid->u2) & 0xff;
344 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
345 id128->bytes[7] = (uuid->u3) & 0xff;
346 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
347 }
348
349 int efi_get_boot_option(
350 uint16_t id,
351 char **title,
352 sd_id128_t *part_uuid,
353 char **path,
354 bool *active) {
355
356 char boot_id[9];
357 _cleanup_free_ uint8_t *buf = NULL;
358 size_t l;
359 struct boot_option *header;
360 size_t title_size;
361 _cleanup_free_ char *s = NULL, *p = NULL;
362 sd_id128_t p_uuid = SD_ID128_NULL;
363 int r;
364
365 xsprintf(boot_id, "Boot%04X", id);
366 r = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
367 if (r < 0)
368 return r;
369 if (l < sizeof(struct boot_option))
370 return -ENOENT;
371
372 header = (struct boot_option *)buf;
373 title_size = utf16_size(header->title);
374 if (title_size > l - offsetof(struct boot_option, title))
375 return -EINVAL;
376
377 if (title) {
378 s = utf16_to_utf8(header->title, title_size);
379 if (!s)
380 return -ENOMEM;
381 }
382
383 if (header->path_len > 0) {
384 uint8_t *dbuf;
385 size_t dnext;
386
387 dbuf = buf + offsetof(struct boot_option, title) + title_size;
388 dnext = 0;
389 while (dnext < header->path_len) {
390 struct device_path *dpath;
391
392 dpath = (struct device_path *)(dbuf + dnext);
393 if (dpath->length < 4)
394 break;
395
396 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
397 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
398 break;
399
400 dnext += dpath->length;
401
402 /* Type 0x04 – Media Device Path */
403 if (dpath->type != MEDIA_DEVICE_PATH)
404 continue;
405
406 /* Sub-Type 1 – Hard Drive */
407 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
408 /* 0x02 – GUID Partition Table */
409 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
410 continue;
411
412 /* 0x02 – GUID signature */
413 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
414 continue;
415
416 if (part_uuid)
417 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
418 continue;
419 }
420
421 /* Sub-Type 4 – File Path */
422 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
423 p = utf16_to_utf8(dpath->path, dpath->length-4);
424 efi_tilt_backslashes(p);
425 continue;
426 }
427 }
428 }
429
430 if (title) {
431 *title = s;
432 s = NULL;
433 }
434 if (part_uuid)
435 *part_uuid = p_uuid;
436 if (path) {
437 *path = p;
438 p = NULL;
439 }
440 if (active)
441 *active = !!(header->attr & LOAD_OPTION_ACTIVE);
442
443 return 0;
444 }
445
446 static void to_utf16(uint16_t *dest, const char *src) {
447 int i;
448
449 for (i = 0; src[i] != '\0'; i++)
450 dest[i] = src[i];
451 dest[i] = '\0';
452 }
453
454 struct guid {
455 uint32_t u1;
456 uint16_t u2;
457 uint16_t u3;
458 uint8_t u4[8];
459 } _packed_;
460
461 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
462 struct guid *uuid = guid;
463
464 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
465 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
466 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
467 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
468 }
469
470 static uint16_t *tilt_slashes(uint16_t *s) {
471 uint16_t *p;
472
473 for (p = s; *p; p++)
474 if (*p == '/')
475 *p = '\\';
476
477 return s;
478 }
479
480 int efi_add_boot_option(uint16_t id, const char *title,
481 uint32_t part, uint64_t pstart, uint64_t psize,
482 sd_id128_t part_uuid, const char *path) {
483 char boot_id[9];
484 size_t size;
485 size_t title_len;
486 size_t path_len;
487 struct boot_option *option;
488 struct device_path *devicep;
489 _cleanup_free_ char *buf = NULL;
490
491 title_len = (strlen(title)+1) * 2;
492 path_len = (strlen(path)+1) * 2;
493
494 buf = calloc(sizeof(struct boot_option) + title_len +
495 sizeof(struct drive_path) +
496 sizeof(struct device_path) + path_len, 1);
497 if (!buf)
498 return -ENOMEM;
499
500 /* header */
501 option = (struct boot_option *)buf;
502 option->attr = LOAD_OPTION_ACTIVE;
503 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
504 offsetof(struct device_path, path) + path_len +
505 offsetof(struct device_path, path);
506 to_utf16(option->title, title);
507 size = offsetof(struct boot_option, title) + title_len;
508
509 /* partition info */
510 devicep = (struct device_path *)(buf + size);
511 devicep->type = MEDIA_DEVICE_PATH;
512 devicep->sub_type = MEDIA_HARDDRIVE_DP;
513 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
514 devicep->drive.part_nr = part;
515 devicep->drive.part_start = pstart;
516 devicep->drive.part_size = psize;
517 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
518 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
519 id128_to_efi_guid(part_uuid, devicep->drive.signature);
520 size += devicep->length;
521
522 /* path to loader */
523 devicep = (struct device_path *)(buf + size);
524 devicep->type = MEDIA_DEVICE_PATH;
525 devicep->sub_type = MEDIA_FILEPATH_DP;
526 devicep->length = offsetof(struct device_path, path) + path_len;
527 to_utf16(devicep->path, path);
528 tilt_slashes(devicep->path);
529 size += devicep->length;
530
531 /* end of path */
532 devicep = (struct device_path *)(buf + size);
533 devicep->type = END_DEVICE_PATH_TYPE;
534 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
535 devicep->length = offsetof(struct device_path, path);
536 size += devicep->length;
537
538 xsprintf(boot_id, "Boot%04X", id);
539 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
540 }
541
542 int efi_remove_boot_option(uint16_t id) {
543 char boot_id[9];
544
545 xsprintf(boot_id, "Boot%04X", id);
546 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
547 }
548
549 int efi_get_boot_order(uint16_t **order) {
550 _cleanup_free_ void *buf = NULL;
551 size_t l;
552 int r;
553
554 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
555 if (r < 0)
556 return r;
557
558 if (l <= 0)
559 return -ENOENT;
560
561 if (l % sizeof(uint16_t) > 0 ||
562 l / sizeof(uint16_t) > INT_MAX)
563 return -EINVAL;
564
565 *order = TAKE_PTR(buf);
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 }