chiark / gitweb /
shared/utf8: merge implementations, remove cruft
[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 -errno;
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         if (title) {
235                 s = utf16_to_utf8(header->title, title_size);
236                 if (!s) {
237                         err = -ENOMEM;
238                         goto err;
239                 }
240         }
241
242         if (header->path_len > 0) {
243                 uint8_t *dbuf;
244                 size_t dnext;
245
246                 dbuf = buf + offsetof(struct boot_option, title) + title_size;
247                 dnext = 0;
248                 while (dnext < header->path_len) {
249                         struct device_path *dpath;
250
251                         dpath = (struct device_path *)(dbuf + dnext);
252                         if (dpath->length < 4)
253                                 break;
254
255                         /* Type 0x7F â€“ End of Hardware Device Path, Sub-Type 0xFF â€“ End Entire Device Path */
256                         if (dpath->type == 0x7f && dpath->sub_type == 0xff)
257                                 break;
258
259                         dnext += dpath->length;
260
261                         /* Type 0x04 â€“ Media Device Path */
262                         if (dpath->type != 0x04)
263                                 continue;
264
265                         /* Sub-Type 1 â€“ Hard Drive */
266                         if (dpath->sub_type == 0x01) {
267                                 /* 0x02 â€“ GUID Partition Table */
268                                 if (dpath->drive.mbr_type != 0x02)
269                                         continue;
270
271                                 /* 0x02 â€“ GUID signature */
272                                 if (dpath->drive.signature_type != 0x02)
273                                         continue;
274
275                                 if (part_uuid)
276                                         efi_guid_to_id128(dpath->drive.signature, &p_uuid);
277                                 continue;
278                         }
279
280                         /* Sub-Type 4 â€“ File Path */
281                         if (dpath->sub_type == 0x04 && !p && path) {
282                                 p = utf16_to_utf8(dpath->path, dpath->length-4);
283                                 continue;
284                         }
285                 }
286         }
287
288         if (title)
289                 *title = s;
290         if (part_uuid)
291                 *part_uuid = p_uuid;
292         if (path)
293                 *path = p;
294
295         return 0;
296 err:
297         free(s);
298         free(p);
299         return err;
300 }
301
302 int efi_get_boot_order(uint16_t **order) {
303         void *buf;
304         size_t l;
305         int r;
306
307         r = efi_get_variable(EFI_VENDOR_GLOBAL, "BootOrder", NULL, &buf, &l);
308         if (r < 0)
309                 return r;
310
311         if (l <= 0) {
312                 free(buf);
313                 return -ENOENT;
314         }
315
316         if ((l % sizeof(uint16_t) > 0) ||
317             (l / sizeof(uint16_t) > INT_MAX)) {
318                 free(buf);
319                 return -EINVAL;
320         }
321
322         *order = buf;
323         return (int) (l / sizeof(uint16_t));
324 }
325
326 static int boot_id_hex(const char s[4]) {
327         int i;
328         int id = 0;
329
330         for (i = 0; i < 4; i++)
331                 if (s[i] >= '0' && s[i] <= '9')
332                         id |= (s[i] - '0') << (3 - i) * 4;
333                 else if (s[i] >= 'A' && s[i] <= 'F')
334                         id |= (s[i] - 'A' + 10) << (3 - i) * 4;
335                 else
336                         return -1;
337
338         return id;
339 }
340
341 static int cmp_uint16(const void *_a, const void *_b) {
342         const uint16_t *a = _a, *b = _b;
343
344         return (int)*a - (int)*b;
345 }
346
347 int efi_get_boot_options(uint16_t **options) {
348         _cleanup_closedir_ DIR *dir = NULL;
349         struct dirent *de;
350         uint16_t *list = NULL;
351         int count = 0, r;
352
353         assert(options);
354
355         dir = opendir("/sys/firmware/efi/efivars/");
356         if (!dir)
357                 return -errno;
358
359         FOREACH_DIRENT(de, dir, r = -errno; goto fail) {
360                 int id;
361                 uint16_t *t;
362
363                 if (strncmp(de->d_name, "Boot", 4) != 0)
364                         continue;
365
366                 if (strlen(de->d_name) != 45)
367                         continue;
368
369                 if (strcmp(de->d_name + 8, "-8be4df61-93ca-11d2-aa0d-00e098032b8c") != 0)
370                         continue;
371
372                 id = boot_id_hex(de->d_name + 4);
373                 if (id < 0)
374                         continue;
375
376                 t = realloc(list, (count + 1) * sizeof(uint16_t));
377                 if (!t) {
378                         r = -ENOMEM;
379                         goto fail;
380                 }
381
382                 list = t;
383                 list[count ++] = id;
384         }
385
386         qsort(list, count, sizeof(uint16_t), cmp_uint16);
387
388         *options = list;
389         return count;
390
391 fail:
392         free(list);
393         return r;
394 }
395
396 static int read_usec(sd_id128_t vendor, const char *name, usec_t *u) {
397         _cleanup_free_ char *j = NULL;
398         int r;
399         uint64_t x;
400
401         assert(name);
402         assert(u);
403
404         r = efi_get_variable_string(EFI_VENDOR_LOADER, name, &j);
405         if (r < 0)
406                 return r;
407
408         r = safe_atou64(j, &x);
409         if (r < 0)
410                 return r;
411
412         *u = x;
413         return 0;
414 }
415
416 static int get_boot_usec(usec_t *firmware, usec_t *loader) {
417         uint64_t x, y;
418         int r;
419
420         assert(firmware);
421         assert(loader);
422
423         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeInitUSec", &x);
424         if (r < 0)
425                 return r;
426
427         r = read_usec(EFI_VENDOR_LOADER, "LoaderTimeExecUSec", &y);
428         if (r < 0)
429                 return r;
430
431         if (y == 0 || y < x)
432                 return -EIO;
433
434         if (y > USEC_PER_HOUR)
435                 return -EIO;
436
437         *firmware = x;
438         *loader = y;
439
440         return 0;
441 }
442
443 int efi_get_boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {
444         usec_t x, y, a;
445         int r;
446         dual_timestamp _n;
447
448         assert(firmware);
449         assert(loader);
450
451         if (!n) {
452                 dual_timestamp_get(&_n);
453                 n = &_n;
454         }
455
456         r = get_boot_usec(&x, &y);
457         if (r < 0)
458                 return r;
459
460         /* Let's convert this to timestamps where the firmware
461          * began/loader began working. To make this more confusing:
462          * since usec_t is unsigned and the kernel's monotonic clock
463          * begins at kernel initialization we'll actually initialize
464          * the monotonic timestamps here as negative of the actual
465          * value. */
466
467         firmware->monotonic = y;
468         loader->monotonic = y - x;
469
470         a = n->monotonic + firmware->monotonic;
471         firmware->realtime = n->realtime > a ? n->realtime - a : 0;
472
473         a = n->monotonic + loader->monotonic;
474         loader->realtime = n->realtime > a ? n->realtime - a : 0;
475
476         return 0;
477 }
478
479 int efi_get_loader_device_part_uuid(sd_id128_t *u) {
480         _cleanup_free_ char *p = NULL;
481         int r, parsed[16];
482         unsigned i;
483
484         assert(u);
485
486         r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderDevicePartUUID", &p);
487         if (r < 0)
488                 return r;
489
490         if (sscanf(p, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
491                    &parsed[0], &parsed[1], &parsed[2], &parsed[3],
492                    &parsed[4], &parsed[5], &parsed[6], &parsed[7],
493                    &parsed[8], &parsed[9], &parsed[10], &parsed[11],
494                    &parsed[12], &parsed[13], &parsed[14], &parsed[15]) != 16)
495                 return -EIO;
496
497         for (i = 0; i < ELEMENTSOF(parsed); i++)
498                 u->bytes[i] = parsed[i];
499
500         return 0;
501 }
502
503 #endif