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