1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <unistd.h>
4 
5 #include "alloc-util.h"
6 #include "dirent-util.h"
7 #include "efi-api.h"
8 #include "efivars.h"
9 #include "fd-util.h"
10 #include "sort-util.h"
11 #include "stat-util.h"
12 #include "stdio-util.h"
13 #include "utf8.h"
14 
15 #if ENABLE_EFI
16 
17 #define LOAD_OPTION_ACTIVE            0x00000001
18 #define MEDIA_DEVICE_PATH                   0x04
19 #define MEDIA_HARDDRIVE_DP                  0x01
20 #define MEDIA_FILEPATH_DP                   0x04
21 #define SIGNATURE_TYPE_GUID                 0x02
22 #define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
23 #define END_DEVICE_PATH_TYPE                0x7f
24 #define END_ENTIRE_DEVICE_PATH_SUBTYPE      0xff
25 
26 #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI UINT64_C(0x0000000000000001)
27 
28 #define boot_option__contents                   \
29         {                                       \
30                 uint32_t attr;                  \
31                 uint16_t path_len;              \
32                 uint16_t title[];               \
33         }
34 
35 struct boot_option boot_option__contents;
36 struct boot_option__packed boot_option__contents _packed_;
37 assert_cc(offsetof(struct boot_option, title) == offsetof(struct boot_option__packed, title));
38 /* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so
39  * the *size* of the structure should not be used anywhere below. */
40 
41 struct drive_path {
42         uint32_t part_nr;
43         uint64_t part_start;
44         uint64_t part_size;
45         char signature[16];
46         uint8_t mbr_type;
47         uint8_t signature_type;
48 } _packed_;
49 
50 #define device_path__contents                           \
51         {                                               \
52                 uint8_t type;                           \
53                 uint8_t sub_type;                       \
54                 uint16_t length;                        \
55                 union {                                 \
56                         uint16_t path[0];               \
57                         struct drive_path drive;        \
58                 };                                      \
59         }
60 
61 struct device_path device_path__contents;
62 struct device_path__packed device_path__contents _packed_;
63 assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed));
64 
efi_reboot_to_firmware_supported(void)65 int efi_reboot_to_firmware_supported(void) {
66         _cleanup_free_ void *v = NULL;
67         static int cache = -1;
68         uint64_t b;
69         size_t s;
70         int r;
71 
72         if (cache > 0)
73                 return 0;
74         if (cache == 0)
75                 return -EOPNOTSUPP;
76 
77         if (!is_efi_boot())
78                 goto not_supported;
79 
80         r = efi_get_variable(EFI_GLOBAL_VARIABLE(OsIndicationsSupported), NULL, &v, &s);
81         if (r == -ENOENT)
82                 goto not_supported; /* variable doesn't exist? it's not supported then */
83         if (r < 0)
84                 return r;
85         if (s != sizeof(uint64_t))
86                 return -EINVAL;
87 
88         b = *(uint64_t*) v;
89         if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
90                 goto not_supported; /* bit unset? it's not supported then */
91 
92         cache = 1;
93         return 0;
94 
95 not_supported:
96         cache = 0;
97         return -EOPNOTSUPP;
98 }
99 
get_os_indications(uint64_t * ret)100 static int get_os_indications(uint64_t *ret) {
101         static struct stat cache_stat = {};
102         _cleanup_free_ void *v = NULL;
103         static uint64_t cache;
104         struct stat new_stat;
105         size_t s;
106         int r;
107 
108         assert(ret);
109 
110         /* Let's verify general support first */
111         r = efi_reboot_to_firmware_supported();
112         if (r < 0)
113                 return r;
114 
115         /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
116         if (stat(EFIVAR_PATH(EFI_GLOBAL_VARIABLE(OsIndications)), &new_stat) < 0) {
117                 if (errno != ENOENT)
118                         return -errno;
119 
120                 /* Doesn't exist? Then we can exit early (also see below) */
121                 *ret = 0;
122                 return 0;
123 
124         } else if (stat_inode_unmodified(&new_stat, &cache_stat)) {
125                 /* inode didn't change, we can return the cached value */
126                 *ret = cache;
127                 return 0;
128         }
129 
130         r = efi_get_variable(EFI_GLOBAL_VARIABLE(OsIndications), NULL, &v, &s);
131         if (r == -ENOENT) {
132                 /* Some firmware implementations that do support OsIndications and report that with
133                  * OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's
134                  * pretend it's 0 then, to hide this implementation detail. Note that this call will return
135                  * -ENOENT then only if the support for OsIndications is missing entirely, as determined by
136                  * efi_reboot_to_firmware_supported() above. */
137                 *ret = 0;
138                 return 0;
139         }
140         if (r < 0)
141                 return r;
142         if (s != sizeof(uint64_t))
143                 return -EINVAL;
144 
145         cache_stat = new_stat;
146         *ret = cache = *(uint64_t *)v;
147         return 0;
148 }
149 
efi_get_reboot_to_firmware(void)150 int efi_get_reboot_to_firmware(void) {
151         int r;
152         uint64_t b;
153 
154         r = get_os_indications(&b);
155         if (r < 0)
156                 return r;
157 
158         return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
159 }
160 
efi_set_reboot_to_firmware(bool value)161 int efi_set_reboot_to_firmware(bool value) {
162         int r;
163         uint64_t b, b_new;
164 
165         r = get_os_indications(&b);
166         if (r < 0)
167                 return r;
168 
169         b_new = UPDATE_FLAG(b, EFI_OS_INDICATIONS_BOOT_TO_FW_UI, value);
170 
171         /* Avoid writing to efi vars store if we can due to firmware bugs. */
172         if (b != b_new)
173                 return efi_set_variable(EFI_GLOBAL_VARIABLE(OsIndications), &b_new, sizeof(uint64_t));
174 
175         return 0;
176 }
177 
utf16_size(const uint16_t * s,size_t buf_len_bytes)178 static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) {
179         size_t l = 0;
180 
181         /* Returns the size of the string in bytes without the terminating two zero bytes */
182 
183         if (buf_len_bytes % sizeof(uint16_t) != 0)
184                 return -EINVAL;
185 
186         while (l < buf_len_bytes / sizeof(uint16_t)) {
187                 if (s[l] == 0)
188                         return (l + 1) * sizeof(uint16_t);
189                 l++;
190         }
191 
192         return -EINVAL; /* The terminator was not found */
193 }
194 
195 struct guid {
196         uint32_t u1;
197         uint16_t u2;
198         uint16_t u3;
199         uint8_t u4[8];
200 } _packed_;
201 
efi_guid_to_id128(const void * guid,sd_id128_t * id128)202 static void efi_guid_to_id128(const void *guid, sd_id128_t *id128) {
203         uint32_t u1;
204         uint16_t u2, u3;
205         const struct guid *uuid = guid;
206 
207         memcpy(&u1, &uuid->u1, sizeof(uint32_t));
208         id128->bytes[0] = (u1 >> 24) & 0xff;
209         id128->bytes[1] = (u1 >> 16) & 0xff;
210         id128->bytes[2] = (u1 >> 8) & 0xff;
211         id128->bytes[3] = u1 & 0xff;
212         memcpy(&u2, &uuid->u2, sizeof(uint16_t));
213         id128->bytes[4] = (u2 >> 8) & 0xff;
214         id128->bytes[5] = u2 & 0xff;
215         memcpy(&u3, &uuid->u3, sizeof(uint16_t));
216         id128->bytes[6] = (u3 >> 8) & 0xff;
217         id128->bytes[7] = u3 & 0xff;
218         memcpy(&id128->bytes[8], uuid->u4, sizeof(uuid->u4));
219 }
220 
efi_get_boot_option(uint16_t id,char ** ret_title,sd_id128_t * ret_part_uuid,char ** ret_path,bool * ret_active)221 int efi_get_boot_option(
222                 uint16_t id,
223                 char **ret_title,
224                 sd_id128_t *ret_part_uuid,
225                 char **ret_path,
226                 bool *ret_active) {
227 
228         char variable[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
229         _cleanup_free_ uint8_t *buf = NULL;
230         size_t l;
231         struct boot_option *header;
232         ssize_t title_size;
233         _cleanup_free_ char *s = NULL, *p = NULL;
234         sd_id128_t p_uuid = SD_ID128_NULL;
235         int r;
236 
237         if (!is_efi_boot())
238                 return -EOPNOTSUPP;
239 
240         xsprintf(variable, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id);
241         r = efi_get_variable(variable, NULL, (void **)&buf, &l);
242         if (r < 0)
243                 return r;
244         if (l < offsetof(struct boot_option, title))
245                 return -ENOENT;
246 
247         header = (struct boot_option *)buf;
248         title_size = utf16_size(header->title, l - offsetof(struct boot_option, title));
249         if (title_size < 0)
250                 return title_size;
251 
252         if (ret_title) {
253                 s = utf16_to_utf8(header->title, title_size);
254                 if (!s)
255                         return -ENOMEM;
256         }
257 
258         if (header->path_len > 0) {
259                 uint8_t *dbuf;
260                 size_t dnext, doff;
261 
262                 doff = offsetof(struct boot_option, title) + title_size;
263                 dbuf = buf + doff;
264                 if (header->path_len > l - doff)
265                         return -EINVAL;
266 
267                 dnext = 0;
268                 while (dnext < header->path_len) {
269                         struct device_path *dpath;
270 
271                         dpath = (struct device_path *)(dbuf + dnext);
272                         if (dpath->length < 4)
273                                 break;
274 
275                         /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
276                         if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
277                                 break;
278 
279                         dnext += dpath->length;
280 
281                         /* Type 0x04 – Media Device Path */
282                         if (dpath->type != MEDIA_DEVICE_PATH)
283                                 continue;
284 
285                         /* Sub-Type 1 – Hard Drive */
286                         if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
287                                 /* 0x02 – GUID Partition Table */
288                                 if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
289                                         continue;
290 
291                                 /* 0x02 – GUID signature */
292                                 if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
293                                         continue;
294 
295                                 if (ret_part_uuid)
296                                         efi_guid_to_id128(dpath->drive.signature, &p_uuid);
297                                 continue;
298                         }
299 
300                         /* Sub-Type 4 – File Path */
301                         if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && ret_path) {
302                                 p = utf16_to_utf8(dpath->path, dpath->length-4);
303                                 if (!p)
304                                         return  -ENOMEM;
305 
306                                 efi_tilt_backslashes(p);
307                                 continue;
308                         }
309                 }
310         }
311 
312         if (ret_title)
313                 *ret_title = TAKE_PTR(s);
314         if (ret_part_uuid)
315                 *ret_part_uuid = p_uuid;
316         if (ret_path)
317                 *ret_path = TAKE_PTR(p);
318         if (ret_active)
319                 *ret_active = header->attr & LOAD_OPTION_ACTIVE;
320 
321         return 0;
322 }
323 
to_utf16(uint16_t * dest,const char * src)324 static void to_utf16(uint16_t *dest, const char *src) {
325         int i;
326 
327         for (i = 0; src[i] != '\0'; i++)
328                 dest[i] = src[i];
329         dest[i] = '\0';
330 }
331 
id128_to_efi_guid(sd_id128_t id,void * guid)332 static void id128_to_efi_guid(sd_id128_t id, void *guid) {
333         struct guid uuid = {
334                 .u1 = id.bytes[0] << 24 | id.bytes[1] << 16 | id.bytes[2] << 8 | id.bytes[3],
335                 .u2 = id.bytes[4] << 8 | id.bytes[5],
336                 .u3 = id.bytes[6] << 8 | id.bytes[7],
337         };
338         memcpy(uuid.u4, id.bytes+8, sizeof(uuid.u4));
339         memcpy(guid, &uuid, sizeof(uuid));
340 }
341 
tilt_slashes(uint16_t * s)342 static uint16_t *tilt_slashes(uint16_t *s) {
343         for (uint16_t *p = s; *p; p++)
344                 if (*p == '/')
345                         *p = '\\';
346 
347         return s;
348 }
349 
efi_add_boot_option(uint16_t id,const char * title,uint32_t part,uint64_t pstart,uint64_t psize,sd_id128_t part_uuid,const char * path)350 int efi_add_boot_option(
351                 uint16_t id,
352                 const char *title,
353                 uint32_t part,
354                 uint64_t pstart,
355                 uint64_t psize,
356                 sd_id128_t part_uuid,
357                 const char *path) {
358 
359         size_t size, title_len, path_len;
360         _cleanup_free_ char *buf = NULL;
361         struct boot_option *option;
362         struct device_path *devicep;
363         char variable[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
364 
365         if (!is_efi_boot())
366                 return -EOPNOTSUPP;
367 
368         title_len = (strlen(title)+1) * 2;
369         path_len = (strlen(path)+1) * 2;
370 
371         buf = malloc0(offsetof(struct boot_option, title) + title_len +
372                       sizeof(struct drive_path) +
373                       sizeof(struct device_path) + path_len);
374         if (!buf)
375                 return -ENOMEM;
376 
377         /* header */
378         option = (struct boot_option *)buf;
379         option->attr = LOAD_OPTION_ACTIVE;
380         option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
381                            offsetof(struct device_path, path) + path_len +
382                            offsetof(struct device_path, path);
383         to_utf16(option->title, title);
384         size = offsetof(struct boot_option, title) + title_len;
385 
386         /* partition info */
387         devicep = (struct device_path *)(buf + size);
388         devicep->type = MEDIA_DEVICE_PATH;
389         devicep->sub_type = MEDIA_HARDDRIVE_DP;
390         devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
391         memcpy(&devicep->drive.part_nr, &part, sizeof(uint32_t));
392         memcpy(&devicep->drive.part_start, &pstart, sizeof(uint64_t));
393         memcpy(&devicep->drive.part_size, &psize, sizeof(uint64_t));
394         id128_to_efi_guid(part_uuid, devicep->drive.signature);
395         devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
396         devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
397         size += devicep->length;
398 
399         /* path to loader */
400         devicep = (struct device_path *)(buf + size);
401         devicep->type = MEDIA_DEVICE_PATH;
402         devicep->sub_type = MEDIA_FILEPATH_DP;
403         devicep->length = offsetof(struct device_path, path) + path_len;
404         to_utf16(devicep->path, path);
405         tilt_slashes(devicep->path);
406         size += devicep->length;
407 
408         /* end of path */
409         devicep = (struct device_path *)(buf + size);
410         devicep->type = END_DEVICE_PATH_TYPE;
411         devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
412         devicep->length = offsetof(struct device_path, path);
413         size += devicep->length;
414 
415         xsprintf(variable, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id);
416         return efi_set_variable(variable, buf, size);
417 }
418 
efi_remove_boot_option(uint16_t id)419 int efi_remove_boot_option(uint16_t id) {
420         char variable[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
421 
422         if (!is_efi_boot())
423                 return -EOPNOTSUPP;
424 
425         xsprintf(variable, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id);
426         return efi_set_variable(variable, NULL, 0);
427 }
428 
efi_get_boot_order(uint16_t ** ret_order)429 int efi_get_boot_order(uint16_t **ret_order) {
430         _cleanup_free_ void *buf = NULL;
431         size_t l;
432         int r;
433 
434         assert(ret_order);
435 
436         if (!is_efi_boot())
437                 return -EOPNOTSUPP;
438 
439         r = efi_get_variable(EFI_GLOBAL_VARIABLE(BootOrder), NULL, &buf, &l);
440         if (r < 0)
441                 return r;
442 
443         if (l <= 0)
444                 return -ENOENT;
445 
446         if (l % sizeof(uint16_t) > 0 ||
447             l / sizeof(uint16_t) > INT_MAX)
448                 return -EINVAL;
449 
450         *ret_order = TAKE_PTR(buf);
451         return (int) (l / sizeof(uint16_t));
452 }
453 
efi_set_boot_order(const uint16_t * order,size_t n)454 int efi_set_boot_order(const uint16_t *order, size_t n) {
455 
456         if (!is_efi_boot())
457                 return -EOPNOTSUPP;
458 
459         return efi_set_variable(EFI_GLOBAL_VARIABLE(BootOrder), order, n * sizeof(uint16_t));
460 }
461 
boot_id_hex(const char s[static4])462 static int boot_id_hex(const char s[static 4]) {
463         int id = 0;
464 
465         assert(s);
466 
467         for (int i = 0; i < 4; i++)
468                 if (s[i] >= '0' && s[i] <= '9')
469                         id |= (s[i] - '0') << (3 - i) * 4;
470                 else if (s[i] >= 'A' && s[i] <= 'F')
471                         id |= (s[i] - 'A' + 10) << (3 - i) * 4;
472                 else
473                         return -EINVAL;
474 
475         return id;
476 }
477 
cmp_uint16(const uint16_t * a,const uint16_t * b)478 static int cmp_uint16(const uint16_t *a, const uint16_t *b) {
479         return CMP(*a, *b);
480 }
481 
efi_get_boot_options(uint16_t ** ret_options)482 int efi_get_boot_options(uint16_t **ret_options) {
483         _cleanup_closedir_ DIR *dir = NULL;
484         _cleanup_free_ uint16_t *list = NULL;
485         int count = 0;
486 
487         assert(ret_options);
488 
489         if (!is_efi_boot())
490                 return -EOPNOTSUPP;
491 
492         dir = opendir(EFIVAR_PATH("."));
493         if (!dir)
494                 return -errno;
495 
496         FOREACH_DIRENT(de, dir, return -errno) {
497                 int id;
498 
499                 if (strncmp(de->d_name, "Boot", 4) != 0)
500                         continue;
501 
502                 if (strlen(de->d_name) != 45)
503                         continue;
504 
505                 if (strcmp(de->d_name + 8, EFI_GLOBAL_VARIABLE_STR("")) != 0)  /* generate variable suffix using macro */
506                         continue;
507 
508                 id = boot_id_hex(de->d_name + 4);
509                 if (id < 0)
510                         continue;
511 
512                 if (!GREEDY_REALLOC(list, count + 1))
513                         return -ENOMEM;
514 
515                 list[count++] = id;
516         }
517 
518         typesafe_qsort(list, count, cmp_uint16);
519 
520         *ret_options = TAKE_PTR(list);
521 
522         return count;
523 }
524 
efi_has_tpm2(void)525 bool efi_has_tpm2(void) {
526         static int cache = -1;
527 
528         /* Returns whether the system has a TPM2 chip which is known to the EFI firmware. */
529 
530         if (cache < 0) {
531 
532                 /* First, check if we are on an EFI boot at all. */
533                 if (!is_efi_boot())
534                         cache = false;
535                 else {
536                         /* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see:
537                          * https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf
538                          * This table exists whenever the firmware is hooked up to TPM2. */
539                         cache = access("/sys/firmware/acpi/tables/TPM2", F_OK) >= 0;
540                         if (!cache && errno != ENOENT)
541                                 log_debug_errno(errno, "Unable to test whether /sys/firmware/acpi/tables/TPM2 exists, assuming it doesn't: %m");
542                 }
543         }
544 
545         return cache;
546 }
547 
548 #endif
549