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