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