chiark / gitweb /
Remove networkd checks
[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 = NULL;
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         size_t alloc = 0;
508         int count = 0;
509
510         assert(options);
511
512         dir = opendir("/sys/firmware/efi/efivars/");
513         if (!dir)
514                 return -errno;
515
516         FOREACH_DIRENT(de, dir, return -errno) {
517                 int id;
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                 if (!GREEDY_REALLOC(list, alloc, count + 1))
533                         return -ENOMEM;
534
535                 list[count++] = id;
536         }
537
538         qsort_safe(list, count, sizeof(uint16_t), cmp_uint16);
539
540         *options = list;
541         list = NULL;
542         return count;
543 }
544
545 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
546         _cleanup_free_ char *j = NULL;
547         int r;
548         uint64_t x = 0;
549
550         assert(name);
551         assert(u);
552
553         r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
554         if (r < 0)
555                 return r;
556
557         r = safe_atou64(j, &x);
558         if (r < 0)
559                 return r;
560
561         *u = x;
562         return 0;
563 }
564
565 int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader) {
566         uint64_t x, y;
567         int r;
568
569         assert(firmware);
570         assert(loader);
571
572         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
573         if (r < 0)
574                 return r;
575
576         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
577         if (r < 0)
578                 return r;
579
580         if (y == 0 || y < x)
581                 return -EIO;
582
583         if (y > USEC_PER_HOUR)
584                 return -EIO;
585
586         *firmware = x;
587         *loader = y;
588
589         return 0;
590 }
591
592 int efi_loader_get_device_part_uuid(sd_id128_t *u) {
593         _cleanup_free_ char *p = NULL;
594         int r, parsed[16];
595
596         r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
597         if (r < 0)
598                 return r;
599
600         if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
601                    &parsed[0], &parsed[1], &parsed[2], &parsed[3],
602                    &parsed[4], &parsed[5], &parsed[6], &parsed[7],
603                    &parsed[8], &parsed[9], &parsed[10], &parsed[11],
604                    &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
605                 return -EIO;
606
607         if (u) {
608                 unsigned i;
609
610                 for (i = 0; i < ELEMENTSOF(parsed); i++)
611                         u->bytes[i] = parsed[i];
612         }
613
614         return 0;
615 }
616
617 #endif