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