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