]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efivars.c
remove unused includes
[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 "efivars.h"
29
30 #ifdef ENABLE_EFI
31
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
41 struct boot_option {
42 uint32_t attr;
43 uint16_t path_len;
44 uint16_t title[];
45 } __attribute__((packed));
46
47 struct 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
56 struct 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
66 bool is_efi_boot(void) {
67 return access("/sys/firmware/efi", F_OK) >= 0;
68 }
69
70 static int read_flag(const char *varname) {
71 int r;
72 _cleanup_free_ void *v = NULL;
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
80 if (s != 1)
81 return -EINVAL;
82
83 b = *(uint8_t *)v;
84 r = b > 0;
85 return r;
86 }
87
88 int is_efi_secure_boot(void) {
89 return read_flag("SecureBoot");
90 }
91
92 int is_efi_secure_boot_setup_mode(void) {
93 return read_flag("SetupMode");
94 }
95
96 int efi_get_variable(
97 sd_id128_t vendor,
98 const char *name,
99 uint32_t *attribute,
100 void **value,
101 size_t *size) {
102
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)
132 return -errno;
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);
143 return -errno;
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;
155 *size = (size_t) st.st_size - 4;
156
157 if (attribute)
158 *attribute = a;
159
160 return 0;
161 }
162
163 int 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
215 finish:
216 if (fd >= 0)
217 close(fd);
218 free(buf);
219 free(p);
220 return r;
221 }
222
223 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
224 _cleanup_free_ void *s = NULL;
225 size_t ss = 0;
226 int r;
227 char *x;
228
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;
239 }
240
241 static size_t utf16_size(const uint16_t *s) {
242 size_t l = 0;
243
244 while (s[l] > 0)
245 l++;
246
247 return (l+1) * sizeof(uint16_t);
248 }
249
250 static 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
270 int efi_get_boot_option(
271 uint16_t id,
272 char **title,
273 sd_id128_t *part_uuid,
274 char **path,
275 bool *active) {
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
301 char boot_id[9];
302 _cleanup_free_ uint8_t *buf = NULL;
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;
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;
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
323 if (title) {
324 s = utf16_to_utf8(header->title, title_size);
325 if (!s) {
326 err = -ENOMEM;
327 goto err;
328 }
329 }
330
331 if (header->path_len > 0) {
332 uint8_t *dbuf;
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 */
345 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
346 break;
347
348 dnext += dpath->length;
349
350 /* Type 0x04 – Media Device Path */
351 if (dpath->type != MEDIA_DEVICE_PATH)
352 continue;
353
354 /* Sub-Type 1 – Hard Drive */
355 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
356 /* 0x02 – GUID Partition Table */
357 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
358 continue;
359
360 /* 0x02 – GUID signature */
361 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
362 continue;
363
364 if (part_uuid)
365 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
366 continue;
367 }
368
369 /* Sub-Type 4 – File Path */
370 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
371 p = utf16_to_utf8(dpath->path, dpath->length-4);
372 efi_tilt_backslashes(p);
373 continue;
374 }
375 }
376 }
377
378 if (title)
379 *title = s;
380 if (part_uuid)
381 *part_uuid = p_uuid;
382 if (path)
383 *path = p;
384 if (active)
385 *active = !!header->attr & LOAD_OPTION_ACTIVE;
386
387 return 0;
388 err:
389 free(s);
390 free(p);
391 return err;
392 }
393
394 static 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
402 struct guid {
403 uint32_t u1;
404 uint16_t u2;
405 uint16_t u3;
406 uint8_t u4[8];
407 } __attribute__((packed));
408
409 static 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
418 static 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
428 char *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
438 int 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
502 finish:
503 free(buf);
504 return err;
505 }
506
507 int 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
514 int efi_get_boot_order(uint16_t **order) {
515 void *buf;
516 size_t l;
517 int r;
518
519 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
520 if (r < 0)
521 return r;
522
523 if (l <= 0) {
524 free(buf);
525 return -ENOENT;
526 }
527
528 if ((l % sizeof(uint16_t) > 0) ||
529 (l / sizeof(uint16_t) > INT_MAX)) {
530 free(buf);
531 return -EINVAL;
532 }
533
534 *order = buf;
535 return (int) (l / sizeof(uint16_t));
536 }
537
538 int 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
542 static 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
552 return -EINVAL;
553
554 return id;
555 }
556
557 static int cmp_uint16(const void *_a, const void *_b) {
558 const uint16_t *a = _a, *b = _b;
559
560 return (int)*a - (int)*b;
561 }
562
563 int efi_get_boot_options(uint16_t **options) {
564 _cleanup_closedir_ DIR *dir = NULL;
565 struct dirent *de;
566 uint16_t *list = NULL;
567 int count = 0, r;
568
569 assert(options);
570
571 dir = opendir("/sys/firmware/efi/efivars/");
572 if (!dir)
573 return -errno;
574
575 FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
576 int id;
577 uint16_t *t;
578
579 if (strncmp(de->d_name, "Boot", 4) != 0)
580 continue;
581
582 if (strlen(de->d_name) != 45)
583 continue;
584
585 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
586 continue;
587
588 id = boot_id_hex(de->d_name + 4);
589 if (id < 0)
590 continue;
591
592 t = realloc(list, (count + 1) * sizeof(uint16_t));
593 if (!t) {
594 r = -ENOMEM;
595 goto fail;
596 }
597
598 list = t;
599 list[count ++] = id;
600 }
601
602 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
603
604 *options = list;
605 return count;
606
607 fail:
608 free(list);
609 return r;
610 }
611
612 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
613 _cleanup_free_ char *j = NULL;
614 int r;
615 uint64_t x = 0;
616
617 assert(name);
618 assert(u);
619
620 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
621 if (r < 0)
622 return r;
623
624 r = safe_atou64(j, &x);
625 if (r < 0)
626 return r;
627
628 *u = x;
629 return 0;
630 }
631
632 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
633 uint64_t x, y;
634 int r;
635
636 assert(firmware);
637 assert(loader);
638
639 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
640 if (r < 0)
641 return r;
642
643 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
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
659 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
660 _cleanup_free_ char *p = NULL;
661 int r, parsed[16];
662
663 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
664 if (r < 0)
665 return r;
666
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
674 if (u) {
675 unsigned i;
676
677 for (i = 0; i < ELEMENTSOF(parsed); i++)
678 u->bytes[i] = parsed[i];
679 }
680
681 return 0;
682 }
683
684 #endif