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