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