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