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