chiark / gitweb /
efivars: use more _cleanup_
[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         _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