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