chiark / gitweb /
4fb77428f22a2b94d79f1ca349a225b40d898582
[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 "util.h"
28 #include "utf8.h"
29 #include "efivars.h"
30
31 #ifdef ENABLE_EFI
32
33 bool is_efi_boot(void) {
34         return access("/sys/firmware/efi", F_OK) >= 0;
35 }
36
37 static int read_flag(const char *varname) {
38         int r;
39         void *v;
40         size_t s;
41         uint8_t b;
42
43         r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
44         if (r < 0)
45                 return r;
46
47         if (s != 1) {
48                 r = -EINVAL;
49                 goto finish;
50         }
51
52         b = *(uint8_t *)v;
53         r = b > 0;
54 finish:
55         free(v);
56         return r;
57 }
58
59 int is_efi_secure_boot(void) {
60         return read_flag("SecureBoot");
61 }
62
63 int is_efi_secure_boot_setup_mode(void) {
64         return read_flag("SetupMode");
65 }
66
67 int efi_get_variable(
68                 sd_id128_t vendor,
69                 const char *name,
70                 uint32_t *attribute,
71                 void **value,
72                 size_t *size) {
73
74         _cleanup_close_ int fd = -1;
75         _cleanup_free_ char *p = NULL;
76         uint32_t a;
77         ssize_t n;
78         struct stat st;
79         void *r;
80
81         assert(name);
82         assert(value);
83         assert(size);
84
85         if (asprintf(&p,
86                      "/sys/firmware/efi/efivars/%s-%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
87                      name, SD_ID128_FORMAT_VAL(vendor)) < 0)
88                 return -ENOMEM;
89
90         fd = open(p, O_RDONLY|O_NOCTTY|O_CLOEXEC);
91         if (fd < 0)
92                 return -errno;
93
94         if (fstat(fd, &st) < 0)
95                 return -errno;
96         if (st.st_size < 4)
97                 return -EIO;
98         if (st.st_size > 4*1024*1024 + 4)
99                 return -E2BIG;
100
101         n = read(fd, &a, sizeof(a));
102         if (n < 0)
103                 return -errno;
104         if (n != sizeof(a))
105                 return -EIO;
106
107         r = malloc(st.st_size - 4 + 2);
108         if (!r)
109                 return -ENOMEM;
110
111         n = read(fd, r, (size_t) st.st_size - 4);
112         if (n < 0) {
113                 free(r);
114                 return (int) -n;
115         }
116         if (n != (ssize_t) st.st_size - 4) {
117                 free(r);
118                 return -EIO;
119         }
120
121         /* Always NUL terminate (2 bytes, to protect UTF-16) */
122         ((char*) r)[st.st_size - 4] = 0;
123         ((char*) r)[st.st_size - 4 + 1] = 0;
124
125         *value = r;
126         *size = (size_t) st.st_size - 4;
127
128         if (attribute)
129                 *attribute = a;
130
131         return 0;
132 }
133
134 int efi_get_variable_string(sd_id128_t vendor, const char *name, char **p) {
135         _cleanup_free_ void *s = NULL;
136         size_t ss;
137         int r;
138         char *x;
139
140         r = efi_get_variable(vendor, name, NULL, &s, &ss);
141         if (r < 0)
142                 return r;
143
144         x = utf16_to_utf8(s, ss);
145         if (!x)
146                 return -ENOMEM;
147
148         *p = x;
149         return 0;
150 }
151
152 static size_t utf16_size(const uint16_t *s) {
153         size_t l = 0;
154
155         while (s[l] > 0)
156                 l++;
157
158         return (l+1) * sizeof(uint16_t);
159 }
160
161 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
162         struct uuid {
163                 uint32_t u1;
164                 uint16_t u2;
165                 uint16_t u3;
166                 uint8_t u4[8];
167         } _packed_;
168         const struct uuid *uuid = guid;
169
170         id128->bytes[0] = (uuid->u1 >> 24) & 0xff;
171         id128->bytes[1] = (uuid->u1 >> 16) & 0xff;
172         id128->bytes[2] = (uuid->u1 >> 8) & 0xff;
173         id128->bytes[3] = (uuid->u1) & 0xff;
174         id128->bytes[4] = (uuid->u2 >> 8) & 0xff;
175         id128->bytes[5] = (uuid->u2) & 0xff;
176         id128->bytes[6] = (uuid->u3 >> 8) & 0xff;
177         id128->bytes[7] = (uuid->u3) & 0xff;
178         memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
179 }
180
181 int efi_get_boot_option(
182                 uint16_t id,
183                 char **title,
184                 sd_id128_t *part_uuid,
185                 char **path) {
186
187         struct boot_option {
188                 uint32_t attr;
189                 uint16_t path_len;
190                 uint16_t title[];
191         } _packed_;
192
193         struct drive_path {
194                 uint32_t part_nr;
195                 uint64_t part_start;
196                 uint64_t part_size;
197                 char signature[16];
198                 uint8_t mbr_type;
199                 uint8_t signature_type;
200         } _packed_;
201
202         struct device_path {
203                 uint8_t type;
204                 uint8_t sub_type;
205                 uint16_t length;
206                 union {
207                         uint16_t path[0];
208                         struct drive_path drive;
209                 };
210         } _packed_;
211
212         char boot_id[9];
213         _cleanup_free_ uint8_t *buf = NULL;
214         size_t l;
215         struct boot_option *header;
216         size_t title_size;
217         char *s = NULL;
218         char *p = NULL;
219         sd_id128_t p_uuid = SD_ID128_NULL;
220         int err;
221
222         snprintf(boot_id, sizeof(boot_id), "Boot%04X", id);
223         err = efi_get_variable(EFI_VENDOR_GLOBAL, boot_id, NULL, (void **)&buf, &l);
224         if (err < 0)
225                 return err;
226         if (l < sizeof(struct boot_option))
227                 return -ENOENT;
228
229         header = (struct boot_option *)buf;
230         title_size = utf16_size(header->title);
231         if (title_size > l - offsetof(struct boot_option, title))
232                 return -EINVAL;
233
234         s = utf16_to_utf8(header->title, title_size);
235         if (!s) {
236                 err = -ENOMEM;
237                 goto err;
238         }
239
240         if (header->path_len > 0) {
241                 uint8_t *dbuf;
242                 size_t dnext;
243
244                 dbuf = buf + offsetof(struct boot_option, title) + title_size;
245                 dnext = 0;
246                 while (dnext < header->path_len) {
247                         struct device_path *dpath;
248
249                         dpath = (struct device_path *)(dbuf + dnext);
250                         if (dpath->length < 4)
251                                 break;
252
253                         /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
254                         if (dpath->type == 0x7f && dpath->sub_type == 0xff)
255                                 break;
256
257                         dnext += dpath->length;
258
259                         /* Type 0x04 – Media Device Path */
260                         if (dpath->type != 0x04)
261                                 continue;
262
263                         /* Sub-Type 1 – Hard Drive */
264                         if (dpath->sub_type == 0x01) {
265                                 /* 0x02 – GUID Partition Table */
266                                 if (dpath->drive.mbr_type != 0x02)
267                                         continue;
268
269                                 /* 0x02 – GUID signature */
270                                 if (dpath->drive.signature_type != 0x02)
271                                         continue;
272
273                                 efi_guid_to_id128(dpath->drive.signature, &p_uuid);
274                                 continue;
275                         }
276
277                         /* Sub-Type 4 – File Path */
278                         if (dpath->sub_type == 0x04) {
279                                 p = utf16_to_utf8(dpath->path, dpath->length-4);
280                                 continue;
281                         }
282                 }
283         }
284
285         if (title)
286                 *title = s;
287         if (part_uuid)
288                 *part_uuid = p_uuid;
289         if (path)
290                 *path = p;
291
292         return 0;
293 err:
294         free(s);
295         free(p);
296         return err;
297 }
298
299 int efi_get_boot_order(uint16_t **order) {
300         void *buf;
301         size_t l;
302         int r;
303
304         r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
305         if (r < 0)
306                 return r;
307
308         if (l <= 0) {
309                 free(buf);
310                 return -ENOENT;
311         }
312
313         if ((l % sizeof(uint16_t) > 0) ||
314             (l / sizeof(uint16_t) > INT_MAX)) {
315                 free(buf);
316                 return -EINVAL;
317         }
318
319         *order = buf;
320         return (int) (l / sizeof(uint16_t));
321 }
322
323 static int boot_id_hex(const char s[4]) {
324         int i;
325         int id = 0;
326
327         for (i = 0; i < 4; i++)
328                 if (s[i] >= '0' && s[i] <= '9')
329                         id |= (s[i] - '0') << (3 - i) * 4;
330                 else if (s[i] >= 'A' && s[i] <= 'F')
331                         id |= (s[i] - 'A' + 10) << (3 - i) * 4;
332                 else
333                         return -1;
334
335         return id;
336 }
337
338 static int cmp_uint16(const void *_a, const void *_b) {
339         const uint16_t *a = _a, *b = _b;
340
341         return (int)*a - (int)*b;
342 }
343
344 int efi_get_boot_options(uint16_t **options) {
345         _cleanup_closedir_ DIR *dir = NULL;
346         struct dirent *de;
347         uint16_t *list = NULL;
348         int count = 0, r;
349
350         assert(options);
351
352         dir = opendir("/sys/firmware/efi/efivars/");
353         if (!dir)
354                 return -errno;
355
356         FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
357                 int id;
358                 uint16_t *t;
359
360                 if (strncmp(de->d_name, "Boot", 4) != 0)
361                         continue;
362
363                 if (strlen(de->d_name) != 45)
364                         continue;
365
366                 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
367                         continue;
368
369                 id = boot_id_hex(de->d_name + 4);
370                 if (id < 0)
371                         continue;
372
373                 t = realloc(list, (count + 1) * sizeof(uint16_t));
374                 if (!t) {
375                         r = -ENOMEM;
376                         goto fail;
377                 }
378
379                 list = t;
380                 list[count ++] = id;
381         }
382
383         qsort(list, count, sizeof(uint16_t), cmp_uint16);
384
385         *options = list;
386         return count;
387
388 fail:
389         free(list);
390         return r;
391 }
392
393 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
394         _cleanup_free_ char *j = NULL;
395         int r;
396         uint64_t x;
397
398         assert(name);
399         assert(u);
400
401         r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
402         if (r < 0)
403                 return r;
404
405         r = safe_atou64(j, &x);
406         if (r < 0)
407                 return r;
408
409         *u = x;
410         return 0;
411 }
412
413 static int get_boot_usec(usec_t *firmware, usec_t *loader) {
414         uint64_t x, y;
415         int r;
416
417         assert(firmware);
418         assert(loader);
419
420         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
421         if (r < 0)
422                 return r;
423
424         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
425         if (r < 0)
426                 return r;
427
428         if (y == 0 || y < x)
429                 return -EIO;
430
431         if (y > USEC_PER_HOUR)
432                 return -EIO;
433
434         *firmware = x;
435         *loader = y;
436
437         return 0;
438 }
439
440 int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
441         usec_t x, y, a;
442         int r;
443         dual_timestamp _n;
444
445         assert(firmware);
446         assert(loader);
447
448         if (!n) {
449                 dual_timestamp_get(&_n);
450                 n = &_n;
451         }
452
453         r = get_boot_usec(&x, &y);
454         if (r < 0)
455                 return r;
456
457         /* Let's convert this to timestamps where the firmware
458          * began/loader began working. To make this more confusing:
459          * since usec_t is unsigned and the kernel's monotonic clock
460          * begins at kernel initialization we'll actually initialize
461          * the monotonic timestamps here as negative of the actual
462          * value. */
463
464         firmware->monotonic = y;
465         loader->monotonic = y - x;
466
467         a = n->monotonic + firmware->monotonic;
468         firmware->realtime = n->realtime > a ? n->realtime - a : 0;
469
470         a = n->monotonic + loader->monotonic;
471         loader->realtime = n->realtime > a ? n->realtime - a : 0;
472
473         return 0;
474 }
475
476 int efi_get_loader_device_part_uuid(sd_id128_t *u) {
477         _cleanup_free_ char *p = NULL;
478         int r, parsed[16];
479         unsigned i;
480
481         assert(u);
482
483         r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
484         if (r < 0)
485                 return r;
486
487         if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
488                    &parsed[0], &parsed[1], &parsed[2], &parsed[3],
489                    &parsed[4], &parsed[5], &parsed[6], &parsed[7],
490                    &parsed[8], &parsed[9], &parsed[10], &parsed[11],
491                    &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
492                 return -EIO;
493
494         for (i = 0; i < ELEMENTSOF(parsed); i++)
495                 u->bytes[i] = parsed[i];
496
497         return 0;
498 }
499
500 #endif