]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/efivars.c
efivars: modernization
[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 } _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 } _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 } _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 } _packed_ * _cleanup_free_ buf = NULL;
173 _cleanup_free_ char *p = NULL;
174 _cleanup_close_ int fd = -1;
175
176 assert(name);
177
178 if (asprintf(&p,
179 "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
180 name, SD_ID128_FORMAT_VAL(vendor)) < 0)
181 return -ENOMEM;
182
183 if (size == 0) {
184 if (unlink(p) < 0)
185 return -errno;
186 return 0;
187 }
188
189 fd = open(p, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0644);
190 if (fd < 0)
191 return -errno;
192
193 buf = malloc(sizeof(uint32_t) + size);
194 if (!buf)
195 return -ENOMEM;
196
197 buf->attr = EFI_VARIABLE_NON_VOLATILE|EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS;
198 memcpy(buf->buf, value, size);
199
200 return loop_write(fd, buf, sizeof(uint32_t) + size, false);
201 }
202
203 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
204 _cleanup_free_ void *s = NULL;
205 size_t ss = 0;
206 int r;
207 char *x;
208
209 r = efi_get_variable(vendor, name, NULL, &s, &ss);
210 if (r < 0)
211 return r;
212
213 x = utf16_to_utf8(s, ss);
214 if (!x)
215 return -ENOMEM;
216
217 *p = x;
218 return 0;
219 }
220
221 static size_t utf16_size(const uint16_t *s) {
222 size_t l = 0;
223
224 while (s[l] > 0)
225 l++;
226
227 return (l+1) * sizeof(uint16_t);
228 }
229
230 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
231 struct uuid {
232 uint32_t u1;
233 uint16_t u2;
234 uint16_t u3;
235 uint8_t u4[8];
236 } _packed_;
237 const struct uuid *uuid = guid;
238
239 id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
240 id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
241 id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
242 id128->bytes[3] = (uuid->u1) & 0xff;
243 id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
244 id128->bytes[5] = (uuid->u2) & 0xff;
245 id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
246 id128->bytes[7] = (uuid->u3) & 0xff;
247 memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
248 }
249
250 int efi_get_boot_option(
251 uint16_t id,
252 char **title,
253 sd_id128_t *part_uuid,
254 char **path,
255 bool *active) {
256
257 char boot_id[9];
258 _cleanup_free_ uint8_t *buf = NULL;
259 size_t l;
260 struct boot_option *header;
261 size_t title_size;
262 _cleanup_free_ char *s = NULL, *p = NULL;
263 sd_id128_t p_uuid = SD_ID128_NULL;
264 int err;
265
266 xsprintf(boot_id, "Boot%04X", id);
267 err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
268 if (err < 0)
269 return err;
270 if (l < sizeof(struct boot_option))
271 return -ENOENT;
272
273 header = (struct boot_option *)buf;
274 title_size = utf16_size(header->title);
275 if (title_size > l - offsetof(struct boot_option, title))
276 return -EINVAL;
277
278 if (title) {
279 s = utf16_to_utf8(header->title, title_size);
280 if (!s)
281 return -ENOMEM;
282 }
283
284 if (header->path_len > 0) {
285 uint8_t *dbuf;
286 size_t dnext;
287
288 dbuf = buf + offsetof(struct boot_option, title) + title_size;
289 dnext = 0;
290 while (dnext < header->path_len) {
291 struct device_path *dpath;
292
293 dpath = (struct device_path *)(dbuf + dnext);
294 if (dpath->length < 4)
295 break;
296
297 /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
298 if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
299 break;
300
301 dnext += dpath->length;
302
303 /* Type 0x04 – Media Device Path */
304 if (dpath->type != MEDIA_DEVICE_PATH)
305 continue;
306
307 /* Sub-Type 1 – Hard Drive */
308 if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
309 /* 0x02 – GUID Partition Table */
310 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
311 continue;
312
313 /* 0x02 – GUID signature */
314 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
315 continue;
316
317 if (part_uuid)
318 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
319 continue;
320 }
321
322 /* Sub-Type 4 – File Path */
323 if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && path) {
324 p = utf16_to_utf8(dpath->path, dpath->length-4);
325 efi_tilt_backslashes(p);
326 continue;
327 }
328 }
329 }
330
331 if (title) {
332 *title = s;
333 s = NULL;
334 }
335 if (part_uuid)
336 *part_uuid = p_uuid;
337 if (path) {
338 *path = p;
339 p = NULL;
340 }
341 if (active)
342 *active = !!header->attr & LOAD_OPTION_ACTIVE;
343
344 return 0;
345 }
346
347 static void to_utf16(uint16_t *dest, const char *src) {
348 int i;
349
350 for (i = 0; src[i] != '\0'; i++)
351 dest[i] = src[i];
352 dest[i] = '\0';
353 }
354
355 struct guid {
356 uint32_t u1;
357 uint16_t u2;
358 uint16_t u3;
359 uint8_t u4[8];
360 } _packed_;
361
362 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
363 struct guid *uuid = guid;
364
365 uuid->u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3];
366 uuid->u2 = id.bytes[4] << 8 | id.bytes[5];
367 uuid->u3 = id.bytes[6] << 8 | id.bytes[7];
368 memcpy(uuid->u4, id.bytes+8, sizeof(uuid->u4));
369 }
370
371 static uint16_t *tilt_slashes(uint16_t *s) {
372 uint16_t *p;
373
374 for (p = s; *p; p++)
375 if (*p == '/')
376 *p = '\\';
377
378 return s;
379 }
380
381 char *efi_tilt_backslashes(char *s) {
382 char *p;
383
384 for (p = s; *p; p++)
385 if (*p == '\\')
386 *p = '/';
387
388 return s;
389 }
390
391 int efi_add_boot_option(uint16_t id, const char *title,
392 uint32_t part, uint64_t pstart, uint64_t psize,
393 sd_id128_t part_uuid, const char *path) {
394 char boot_id[9];
395 size_t size;
396 size_t title_len;
397 size_t path_len;
398 struct boot_option *option;
399 struct device_path *devicep;
400 _cleanup_free_ char *buf = NULL;
401
402 title_len = (strlen(title)+1) * 2;
403 path_len = (strlen(path)+1) * 2;
404
405 buf = calloc(sizeof(struct boot_option) + title_len +
406 sizeof(struct drive_path) +
407 sizeof(struct device_path) + path_len, 1);
408 if (!buf)
409 return -ENOMEM;
410
411 /* header */
412 option = (struct boot_option *)buf;
413 option->attr = LOAD_OPTION_ACTIVE;
414 option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
415 offsetof(struct device_path, path) + path_len +
416 offsetof(struct device_path, path);
417 to_utf16(option->title, title);
418 size = offsetof(struct boot_option, title) + title_len;
419
420 /* partition info */
421 devicep = (struct device_path *)(buf + size);
422 devicep->type = MEDIA_DEVICE_PATH;
423 devicep->sub_type = MEDIA_HARDDRIVE_DP;
424 devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
425 devicep->drive.part_nr = part;
426 devicep->drive.part_start = pstart;
427 devicep->drive.part_size = psize;
428 devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
429 devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
430 id128_to_efi_guid(part_uuid, devicep->drive.signature);
431 size += devicep->length;
432
433 /* path to loader */
434 devicep = (struct device_path *)(buf + size);
435 devicep->type = MEDIA_DEVICE_PATH;
436 devicep->sub_type = MEDIA_FILEPATH_DP;
437 devicep->length = offsetof(struct device_path, path) + path_len;
438 to_utf16(devicep->path, path);
439 tilt_slashes(devicep->path);
440 size += devicep->length;
441
442 /* end of path */
443 devicep = (struct device_path *)(buf + size);
444 devicep->type = END_DEVICE_PATH_TYPE;
445 devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
446 devicep->length = offsetof(struct device_path, path);
447 size += devicep->length;
448
449 xsprintf(boot_id, "Boot%04X", id);
450 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, buf, size);
451 }
452
453 int efi_remove_boot_option(uint16_t id) {
454 char boot_id[9];
455
456 xsprintf(boot_id, "Boot%04X", id);
457 return efi_set_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, 0);
458 }
459
460 int efi_get_boot_order(uint16_t **order) {
461 void *buf;
462 size_t l;
463 int r;
464
465 r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
466 if (r < 0)
467 return r;
468
469 if (l <= 0) {
470 free(buf);
471 return -ENOENT;
472 }
473
474 if ((l % sizeof(uint16_t) > 0) ||
475 (l / sizeof(uint16_t) > INT_MAX)) {
476 free(buf);
477 return -EINVAL;
478 }
479
480 *order = buf;
481 return (int) (l / sizeof(uint16_t));
482 }
483
484 int efi_set_boot_order(uint16_t *order, size_t n) {
485 return efi_set_variable(EFI_VENDOR_GLOBAL, "BootOrder", order, n * sizeof(uint16_t));
486 }
487
488 static int boot_id_hex(const char s[4]) {
489 int i;
490 int id = 0;
491
492 for (i = 0; i < 4; i++)
493 if (s[i] >= '0' && s[i] <= '9')
494 id |= (s[i] - '0') << (3 - i) * 4;
495 else if (s[i] >= 'A' && s[i] <= 'F')
496 id |= (s[i] - 'A' + 10) << (3 - i) * 4;
497 else
498 return -EINVAL;
499
500 return id;
501 }
502
503 static int cmp_uint16(const void *_a, const void *_b) {
504 const uint16_t *a = _a, *b = _b;
505
506 return (int)*a - (int)*b;
507 }
508
509 int efi_get_boot_options(uint16_t **options) {
510 _cleanup_closedir_ DIR *dir = NULL;
511 struct dirent *de;
512 _cleanup_free_ uint16_t *list = NULL;
513 int count = 0;
514
515 assert(options);
516
517 dir = opendir("/sys/firmware/efi/efivars/");
518 if (!dir)
519 return -errno;
520
521 FOREACH_DIRENT(de, dir, return -errno) {
522 int id;
523 uint16_t *t;
524
525 if (strncmp(de->d_name, "Boot", 4) != 0)
526 continue;
527
528 if (strlen(de->d_name) != 45)
529 continue;
530
531 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
532 continue;
533
534 id = boot_id_hex(de->d_name + 4);
535 if (id < 0)
536 continue;
537
538 t = realloc(list, (count + 1) * sizeof(uint16_t));
539 if (!t)
540 return -ENOMEM;
541
542 list = t;
543 list[count ++] = id;
544 }
545
546 qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
547
548 *options = list;
549 list = NULL;
550 return count;
551 }
552
553 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
554 _cleanup_free_ char *j = NULL;
555 int r;
556 uint64_t x = 0;
557
558 assert(name);
559 assert(u);
560
561 r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
562 if (r < 0)
563 return r;
564
565 r = safe_atou64(j, &x);
566 if (r < 0)
567 return r;
568
569 *u = x;
570 return 0;
571 }
572
573 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
574 uint64_t x, y;
575 int r;
576
577 assert(firmware);
578 assert(loader);
579
580 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
581 if (r < 0)
582 return r;
583
584 r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
585 if (r < 0)
586 return r;
587
588 if (y == 0 || y < x)
589 return -EIO;
590
591 if (y > USEC_PER_HOUR)
592 return -EIO;
593
594 *firmware = x;
595 *loader = y;
596
597 return 0;
598 }
599
600 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
601 _cleanup_free_ char *p = NULL;
602 int r, parsed[16];
603
604 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
605 if (r < 0)
606 return r;
607
608 if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
609 &parsed[0], &parsed[1], &parsed[2], &parsed[3],
610 &parsed[4], &parsed[5], &parsed[6], &parsed[7],
611 &parsed[8], &parsed[9], &parsed[10], &parsed[11],
612 &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
613 return -EIO;
614
615 if (u) {
616 unsigned i;
617
618 for (i = 0; i < ELEMENTSOF(parsed); i++)
619 u->bytes[i] = parsed[i];
620 }
621
622 return 0;
623 }
624
625 #endif