chiark / gitweb /
efivars: modernization
[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_ * _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