chiark / gitweb /
tree-wide: use _packed_ macro instead of raw gcc __attribute__
[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
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_ *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 } _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