Coverage Report

Created: 2026-09-14 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/shared/efi-api.c
Line
Count
Source
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 "efi.h"
9
#include "efivars.h"
10
#include "fd-util.h"
11
#include "fileio.h"
12
#include "log.h"
13
#include "parse-util.h"
14
#include "sort-util.h"
15
#include "stat-util.h"
16
#include "stdio-util.h"
17
#include "string-util.h"
18
#include "tpm2-util.h"                  /* IWYU pragma: keep */
19
#include "utf8.h"
20
21
0
#define EFI_TCG2_BOOT_HASH_ALG_SHA1   0x01
22
0
#define EFI_TCG2_BOOT_HASH_ALG_SHA256 0x02
23
0
#define EFI_TCG2_BOOT_HASH_ALG_SHA384 0x04
24
0
#define EFI_TCG2_BOOT_HASH_ALG_SHA512 0x08
25
26
0
#define LOAD_OPTION_ACTIVE            0x00000001
27
0
#define MEDIA_DEVICE_PATH                   0x04
28
0
#define MEDIA_HARDDRIVE_DP                  0x01
29
0
#define MEDIA_FILEPATH_DP                   0x04
30
0
#define SIGNATURE_TYPE_GUID                 0x02
31
0
#define MBR_TYPE_EFI_PARTITION_TABLE_HEADER 0x02
32
0
#define END_DEVICE_PATH_TYPE                0x7f
33
0
#define END_ENTIRE_DEVICE_PATH_SUBTYPE      0xff
34
35
0
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI UINT64_C(0x0000000000000001)
36
37
#define boot_option__contents                   \
38
        {                                       \
39
                uint32_t attr;                  \
40
                uint16_t path_len;              \
41
                uint16_t title[];               \
42
        }
43
44
struct boot_option boot_option__contents;
45
struct boot_option__packed boot_option__contents _packed_;
46
assert_cc(offsetof(struct boot_option, title) == offsetof(struct boot_option__packed, title));
47
/* sizeof(struct boot_option) != sizeof(struct boot_option__packed), so
48
 * the *size* of the structure should not be used anywhere below. */
49
50
struct drive_path {
51
        uint32_t part_nr;
52
        uint64_t part_start;
53
        uint64_t part_size;
54
        char signature[16];
55
        uint8_t mbr_type;
56
        uint8_t signature_type;
57
} _packed_;
58
59
#define device_path__contents                           \
60
        {                                               \
61
                uint8_t type;                           \
62
                uint8_t sub_type;                       \
63
                uint16_t length;                        \
64
                union {                                 \
65
                        uint16_t path[0];               \
66
                        struct drive_path drive;        \
67
                };                                      \
68
        }
69
70
struct device_path device_path__contents;
71
struct device_path__packed device_path__contents _packed_;
72
assert_cc(sizeof(struct device_path) == sizeof(struct device_path__packed));
73
74
#if ENABLE_EFI
75
0
static int get_os_indications(uint64_t *ret) {
76
0
        static struct stat cache_stat = {};
77
0
        _cleanup_free_ void *v = NULL;
78
0
        static uint64_t cache;
79
0
        struct stat new_stat;
80
0
        size_t s;
81
0
        int r;
82
83
0
        assert(ret);
84
85
        /* Let's verify general support first */
86
0
        r = efi_reboot_to_firmware_supported();
87
0
        if (r < 0)
88
0
                return r;
89
90
        /* stat() the EFI variable, to see if the mtime changed. If it did we need to cache again. */
91
0
        if (stat(EFIVAR_PATH(EFI_GLOBAL_VARIABLE_STR("OsIndications")), &new_stat) < 0) {
92
0
                if (errno != ENOENT)
93
0
                        return -errno;
94
95
                /* Doesn't exist? Then we can exit early (also see below) */
96
0
                *ret = 0;
97
0
                return 0;
98
99
0
        } else if (stat_inode_unmodified(&new_stat, &cache_stat)) {
100
                /* inode didn't change, we can return the cached value */
101
0
                *ret = cache;
102
0
                return 0;
103
0
        }
104
105
0
        r = efi_get_variable(EFI_GLOBAL_VARIABLE_STR("OsIndications"), NULL, &v, &s);
106
0
        if (r == -ENOENT) {
107
                /* Some firmware implementations that do support OsIndications and report that with
108
                 * OsIndicationsSupported will remove the OsIndications variable when it is unset. Let's
109
                 * pretend it's 0 then, to hide this implementation detail. Note that this call will return
110
                 * -ENOENT then only if the support for OsIndications is missing entirely, as determined by
111
                 * efi_reboot_to_firmware_supported() above. */
112
0
                *ret = 0;
113
0
                return 0;
114
0
        }
115
0
        if (r < 0)
116
0
                return r;
117
0
        if (s != sizeof(uint64_t))
118
0
                return -EINVAL;
119
120
0
        cache_stat = new_stat;
121
0
        *ret = cache = *(uint64_t *)v;
122
0
        return 0;
123
0
}
124
125
0
static ssize_t utf16_size(const uint16_t *s, size_t buf_len_bytes) {
126
0
        size_t l = 0;
127
128
        /* Returns the size of the string in bytes without the terminating two zero bytes */
129
130
0
        while (l < buf_len_bytes / sizeof(uint16_t)) {
131
0
                if (s[l] == 0)
132
0
                        return (l + 1) * sizeof(uint16_t);
133
0
                l++;
134
0
        }
135
136
0
        return -EINVAL; /* The terminator was not found */
137
0
}
138
139
0
static void to_utf16(uint16_t *dest, const char *src) {
140
0
        int i;
141
142
0
        for (i = 0; src[i] != '\0'; i++)
143
0
                dest[i] = src[i];
144
0
        dest[i] = '\0';
145
0
}
146
147
0
static uint16_t *tilt_slashes(uint16_t *s) {
148
0
        for (uint16_t *p = s; *p; p++)
149
0
                if (*p == '/')
150
0
                        *p = '\\';
151
152
0
        return s;
153
0
}
154
155
0
static int boot_id_hex(const char s[static 4]) {
156
0
        int id = 0;
157
158
0
        assert(s);
159
160
0
        for (int i = 0; i < 4; i++)
161
0
                if (s[i] >= '0' && s[i] <= '9')
162
0
                        id |= (s[i] - '0') << (3 - i) * 4;
163
0
                else if (s[i] >= 'A' && s[i] <= 'F')
164
0
                        id |= (s[i] - 'A' + 10) << (3 - i) * 4;
165
0
                else
166
0
                        return -EINVAL;
167
168
0
        return id;
169
0
}
170
#endif
171
172
0
int efi_reboot_to_firmware_supported(void) {
173
0
#if ENABLE_EFI
174
0
        _cleanup_free_ void *v = NULL;
175
0
        static int cache = -1;
176
0
        uint64_t b;
177
0
        size_t s;
178
0
        int r;
179
180
0
        if (cache > 0)
181
0
                return 0;
182
0
        if (cache == 0)
183
0
                return -EOPNOTSUPP;
184
185
0
        if (!is_efi_boot())
186
0
                goto not_supported;
187
188
0
        r = efi_get_variable(EFI_GLOBAL_VARIABLE_STR("OsIndicationsSupported"), NULL, &v, &s);
189
0
        if (r == -ENOENT)
190
0
                goto not_supported; /* variable doesn't exist? it's not supported then */
191
0
        if (r < 0)
192
0
                return r;
193
0
        if (s != sizeof(uint64_t))
194
0
                return -EINVAL;
195
196
0
        b = *(uint64_t*) v;
197
0
        if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
198
0
                goto not_supported; /* bit unset? it's not supported then */
199
200
0
        cache = 1;
201
0
        return 0;
202
203
0
not_supported:
204
0
        cache = 0;
205
0
        return -EOPNOTSUPP;
206
#else
207
        return -EOPNOTSUPP;
208
#endif
209
0
}
210
211
0
int efi_get_reboot_to_firmware(void) {
212
0
#if ENABLE_EFI
213
0
        int r;
214
0
        uint64_t b;
215
216
0
        r = get_os_indications(&b);
217
0
        if (r < 0)
218
0
                return r;
219
220
0
        return !!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
221
#else
222
        return -EOPNOTSUPP;
223
#endif
224
0
}
225
226
0
int efi_set_reboot_to_firmware(bool value) {
227
0
#if ENABLE_EFI
228
0
        int r;
229
0
        uint64_t b, b_new;
230
231
0
        r = get_os_indications(&b);
232
0
        if (r < 0)
233
0
                return r;
234
235
0
        b_new = UPDATE_FLAG(b, EFI_OS_INDICATIONS_BOOT_TO_FW_UI, value);
236
237
        /* Avoid writing to efi vars store if we can due to firmware bugs. */
238
0
        if (b != b_new)
239
0
                return efi_set_variable(EFI_GLOBAL_VARIABLE_STR("OsIndications"), &b_new, sizeof(uint64_t));
240
241
0
        return 0;
242
#else
243
        return -EOPNOTSUPP;
244
#endif
245
0
}
246
247
int efi_get_boot_option(
248
                uint16_t id,
249
                char **ret_title,
250
                sd_id128_t *ret_part_uuid,
251
                char **ret_path,
252
0
                bool *ret_active) {
253
0
#if ENABLE_EFI
254
0
        char variable[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
255
0
        _cleanup_free_ uint8_t *buf = NULL;
256
0
        size_t l;
257
0
        struct boot_option *header;
258
0
        ssize_t title_size;
259
0
        _cleanup_free_ char *s = NULL, *p = NULL;
260
0
        sd_id128_t p_uuid = SD_ID128_NULL;
261
0
        int r;
262
263
0
        if (!is_efi_boot())
264
0
                return -EOPNOTSUPP;
265
266
0
        xsprintf(variable, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id);
267
0
        r = efi_get_variable(variable, NULL, (void **)&buf, &l);
268
0
        if (r < 0)
269
0
                return r;
270
0
        if (l < offsetof(struct boot_option, title))
271
0
                return -ENOENT;
272
273
0
        header = (struct boot_option *)buf;
274
0
        title_size = utf16_size(header->title, l - offsetof(struct boot_option, title));
275
0
        if (title_size < 0)
276
0
                return title_size;
277
278
0
        if (ret_title) {
279
0
                s = utf16_to_utf8(header->title, title_size);
280
0
                if (!s)
281
0
                        return -ENOMEM;
282
0
        }
283
284
0
        if (header->path_len > 0) {
285
0
                uint8_t *dbuf;
286
0
                size_t dnext, doff, path_len;
287
288
0
                doff = offsetof(struct boot_option, title) + title_size;
289
0
                dbuf = buf + doff;
290
0
                path_len = MIN((size_t) header->path_len, l - doff);
291
292
0
                dnext = 0;
293
0
                while (dnext < path_len) {
294
0
                        struct device_path *dpath;
295
0
                        size_t remaining = path_len - dnext;
296
297
0
                        if (remaining < offsetof(struct device_path, path))
298
0
                                break;
299
300
0
                        dpath = (struct device_path *)(dbuf + dnext);
301
0
                        if (dpath->length < offsetof(struct device_path, path) ||
302
0
                            dpath->length > remaining)
303
0
                                break;
304
305
                        /* Type 0x7F – End of Hardware Device Path, Sub-Type 0xFF – End Entire Device Path */
306
0
                        if (dpath->type == END_DEVICE_PATH_TYPE && dpath->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
307
0
                                break;
308
309
0
                        dnext += dpath->length;
310
311
                        /* Type 0x04 – Media Device Path */
312
0
                        if (dpath->type != MEDIA_DEVICE_PATH)
313
0
                                continue;
314
315
                        /* Sub-Type 1 – Hard Drive */
316
0
                        if (dpath->sub_type == MEDIA_HARDDRIVE_DP) {
317
0
                                if (dpath->length < offsetof(struct device_path, drive) + sizeof(struct drive_path))
318
0
                                        break;
319
320
                                /* 0x02 – GUID Partition Table */
321
0
                                if (dpath->drive.mbr_type != MBR_TYPE_EFI_PARTITION_TABLE_HEADER)
322
0
                                        continue;
323
324
                                /* 0x02 – GUID signature */
325
0
                                if (dpath->drive.signature_type != SIGNATURE_TYPE_GUID)
326
0
                                        continue;
327
328
0
                                if (ret_part_uuid)
329
0
                                        p_uuid = efi_guid_to_id128(dpath->drive.signature);
330
0
                                continue;
331
0
                        }
332
333
                        /* Sub-Type 4 – File Path */
334
0
                        if (dpath->sub_type == MEDIA_FILEPATH_DP && !p && ret_path) {
335
0
                                p = utf16_to_utf8(dpath->path, dpath->length - offsetof(struct device_path, path));
336
0
                                if (!p)
337
0
                                        return -ENOMEM;
338
339
0
                                efi_tilt_backslashes(p);
340
0
                                continue;
341
0
                        }
342
0
                }
343
0
        }
344
345
0
        if (ret_title)
346
0
                *ret_title = TAKE_PTR(s);
347
0
        if (ret_part_uuid)
348
0
                *ret_part_uuid = p_uuid;
349
0
        if (ret_path)
350
0
                *ret_path = TAKE_PTR(p);
351
0
        if (ret_active)
352
0
                *ret_active = header->attr & LOAD_OPTION_ACTIVE;
353
354
0
        return 0;
355
#else
356
        return -EOPNOTSUPP;
357
#endif
358
0
}
359
360
int efi_add_boot_option(
361
                uint16_t id,
362
                const char *title,
363
                uint32_t part,
364
                uint64_t pstart,
365
                uint64_t psize,
366
                sd_id128_t part_uuid,
367
0
                const char *path) {
368
0
#if ENABLE_EFI
369
0
        size_t size, title_len, path_len;
370
0
        _cleanup_free_ char *buf = NULL;
371
0
        struct boot_option *option;
372
0
        struct device_path *devicep;
373
0
        char variable[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
374
375
0
        if (!is_efi_boot())
376
0
                return -EOPNOTSUPP;
377
378
0
        title_len = (strlen(title)+1) * 2;
379
0
        path_len = (strlen(path)+1) * 2;
380
381
0
        buf = malloc0(offsetof(struct boot_option, title) + title_len +
382
0
                      sizeof(struct drive_path) +
383
0
                      sizeof(struct device_path) + path_len);
384
0
        if (!buf)
385
0
                return -ENOMEM;
386
387
        /* header */
388
0
        option = (struct boot_option *)buf;
389
0
        option->attr = LOAD_OPTION_ACTIVE;
390
0
        option->path_len = offsetof(struct device_path, drive) + sizeof(struct drive_path) +
391
0
                           offsetof(struct device_path, path) + path_len +
392
0
                           offsetof(struct device_path, path);
393
0
        to_utf16(option->title, title);
394
0
        size = offsetof(struct boot_option, title) + title_len;
395
396
        /* partition info */
397
0
        devicep = (struct device_path *)(buf + size);
398
0
        devicep->type = MEDIA_DEVICE_PATH;
399
0
        devicep->sub_type = MEDIA_HARDDRIVE_DP;
400
0
        devicep->length = offsetof(struct device_path, drive) + sizeof(struct drive_path);
401
0
        memcpy(&devicep->drive.part_nr, &part, sizeof(uint32_t));
402
0
        memcpy(&devicep->drive.part_start, &pstart, sizeof(uint64_t));
403
0
        memcpy(&devicep->drive.part_size, &psize, sizeof(uint64_t));
404
0
        efi_id128_to_guid(part_uuid, devicep->drive.signature);
405
0
        devicep->drive.mbr_type = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
406
0
        devicep->drive.signature_type = SIGNATURE_TYPE_GUID;
407
0
        size += devicep->length;
408
409
        /* path to loader */
410
0
        devicep = (struct device_path *)(buf + size);
411
0
        devicep->type = MEDIA_DEVICE_PATH;
412
0
        devicep->sub_type = MEDIA_FILEPATH_DP;
413
0
        devicep->length = offsetof(struct device_path, path) + path_len;
414
0
        to_utf16(devicep->path, path);
415
0
        tilt_slashes(devicep->path);
416
0
        size += devicep->length;
417
418
        /* end of path */
419
0
        devicep = (struct device_path *)(buf + size);
420
0
        devicep->type = END_DEVICE_PATH_TYPE;
421
0
        devicep->sub_type = END_ENTIRE_DEVICE_PATH_SUBTYPE;
422
0
        devicep->length = offsetof(struct device_path, path);
423
0
        size += devicep->length;
424
425
0
        xsprintf(variable, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id);
426
0
        return efi_set_variable(variable, buf, size);
427
#else
428
        return -EOPNOTSUPP;
429
#endif
430
0
}
431
432
0
int efi_remove_boot_option(uint16_t id) {
433
0
#if ENABLE_EFI
434
0
        char variable[STRLEN(EFI_GLOBAL_VARIABLE_STR("Boot")) + 4 + 1];
435
436
0
        if (!is_efi_boot())
437
0
                return -EOPNOTSUPP;
438
439
0
        xsprintf(variable, EFI_GLOBAL_VARIABLE_STR("Boot%04X"), id);
440
0
        return efi_set_variable(variable, NULL, 0);
441
#else
442
        return -EOPNOTSUPP;
443
#endif
444
0
}
445
446
0
int efi_get_boot_order(uint16_t **ret_order) {
447
0
#if ENABLE_EFI
448
0
        _cleanup_free_ void *buf = NULL;
449
0
        size_t l;
450
0
        int r;
451
452
0
        assert(ret_order);
453
454
0
        if (!is_efi_boot())
455
0
                return -EOPNOTSUPP;
456
457
0
        r = efi_get_variable(EFI_GLOBAL_VARIABLE_STR("BootOrder"), NULL, &buf, &l);
458
0
        if (r < 0)
459
0
                return r;
460
461
0
        if (l <= 0)
462
0
                return -ENOENT;
463
464
0
        if (l % sizeof(uint16_t) > 0 ||
465
0
            l / sizeof(uint16_t) > INT_MAX)
466
0
                return -EINVAL;
467
468
0
        *ret_order = TAKE_PTR(buf);
469
0
        return (int) (l / sizeof(uint16_t));
470
#else
471
        return -EOPNOTSUPP;
472
#endif
473
0
}
474
475
0
int efi_set_boot_order(const uint16_t *order, size_t n) {
476
0
#if ENABLE_EFI
477
0
        if (!is_efi_boot())
478
0
                return -EOPNOTSUPP;
479
480
0
        return efi_set_variable(EFI_GLOBAL_VARIABLE_STR("BootOrder"), order, n * sizeof(uint16_t));
481
#else
482
        return -EOPNOTSUPP;
483
#endif
484
0
}
485
486
0
int efi_get_boot_options(uint16_t **ret_options) {
487
0
#if ENABLE_EFI
488
0
        _cleanup_closedir_ DIR *dir = NULL;
489
0
        _cleanup_free_ uint16_t *list = NULL;
490
0
        int count = 0;
491
492
0
        assert(ret_options);
493
494
0
        if (!is_efi_boot())
495
0
                return -EOPNOTSUPP;
496
497
0
        dir = opendir(EFIVAR_PATH("."));
498
0
        if (!dir)
499
0
                return -errno;
500
501
0
        FOREACH_DIRENT(de, dir, return -errno) {
502
0
                int id;
503
504
0
                if (!startswith(de->d_name, "Boot"))
505
0
                        continue;
506
507
0
                if (strlen(de->d_name) != 45)
508
0
                        continue;
509
510
0
                if (!streq(de->d_name + 8, EFI_GLOBAL_VARIABLE_STR(""))) /* generate variable suffix using macro */
511
0
                        continue;
512
513
0
                id = boot_id_hex(de->d_name + 4);
514
0
                if (id < 0)
515
0
                        continue;
516
517
0
                if (!GREEDY_REALLOC(list, count + 1))
518
0
                        return -ENOMEM;
519
520
0
                list[count++] = id;
521
0
        }
522
523
0
        typesafe_qsort(list, count, cmp_uint16);
524
525
0
        *ret_options = TAKE_PTR(list);
526
527
0
        return count;
528
#else
529
        return -EOPNOTSUPP;
530
#endif
531
0
}
532
533
0
int efi_get_active_pcr_banks(uint32_t *ret) {
534
0
#if ENABLE_EFI
535
0
        static uint32_t cache = 0;
536
0
        static bool cache_valid = false;
537
0
        int r;
538
539
        /* Returns the enabled PCR banks as bitmask, as reported by firmware. If the bitmask is returned as
540
         * UINT32_MAX, the firmware supports the TCG protocol, but in a version too old to report this
541
         * information. */
542
543
0
        if (!cache_valid) {
544
0
                _cleanup_free_ char *active_pcr_banks = NULL;
545
0
                r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("LoaderTpm2ActivePcrBanks"), &active_pcr_banks);
546
0
                if (r < 0)
547
0
                        return log_debug_errno(r, "Failed to read LoaderTpm2ActivePcrBanks variable: %m");
548
549
0
                uint32_t efi_bits;
550
0
                r = safe_atou32_full(active_pcr_banks, 16, &efi_bits);
551
0
                if (r < 0)
552
0
                        return log_debug_errno(r, "Failed to parse LoaderTpm2ActivePcrBanks variable: %m");
553
554
0
                if (efi_bits == UINT32_MAX)
555
                        /* UINT32_MAX means that the firmware API doesn't implement GetActivePcrBanks() and caller must guess */
556
0
                        cache = UINT32_MAX;
557
0
                else {
558
                        /* EFI TPM protocol uses different bit values for the hash algorithms, let's convert */
559
0
                        static const struct {
560
0
                                uint32_t efi;
561
0
                                uint32_t tcg;
562
0
                        } table[] = {
563
0
                                { EFI_TCG2_BOOT_HASH_ALG_SHA1,   1U << TPM2_ALG_SHA1   },
564
0
                                { EFI_TCG2_BOOT_HASH_ALG_SHA256, 1U << TPM2_ALG_SHA256 },
565
0
                                { EFI_TCG2_BOOT_HASH_ALG_SHA384, 1U << TPM2_ALG_SHA384 },
566
0
                                { EFI_TCG2_BOOT_HASH_ALG_SHA512, 1U << TPM2_ALG_SHA512 },
567
0
                        };
568
569
0
                        uint32_t tcg_bits = 0;
570
0
                        FOREACH_ELEMENT(t, table)
571
0
                                SET_FLAG(tcg_bits, t->tcg, efi_bits & t->efi);
572
573
0
                        cache = tcg_bits;
574
0
                }
575
576
0
                cache_valid = true;
577
0
        }
578
579
0
        if (ret)
580
0
                *ret = cache;
581
582
0
        return 0;
583
#else
584
        return -EOPNOTSUPP;
585
#endif
586
0
}
587
588
#if ENABLE_EFI
589
0
static int loader_has_tpm2(void) {
590
0
        uint32_t active_pcr_banks;
591
0
        int r;
592
593
0
        r = efi_get_active_pcr_banks(&active_pcr_banks);
594
0
        if (r < 0)
595
0
                return r;
596
597
0
        return active_pcr_banks != 0;
598
0
}
599
#endif
600
601
0
bool efi_has_tpm2(void) {
602
0
#if ENABLE_EFI
603
0
        static int cache = -1;
604
0
        int r;
605
606
        /* Returns whether the system has a TPM2 chip which is known to the EFI firmware. */
607
608
0
        if (cache >= 0)
609
0
                return cache;
610
611
        /* First, check if we are on an EFI boot at all. */
612
0
        if (!is_efi_boot())
613
0
                return (cache = false);
614
615
        /* Secondly, check if the loader told us, as that is the most accurate source of information
616
         * regarding the firmware's setup */
617
0
        r = loader_has_tpm2();
618
0
        if (r >= 0)
619
0
                return (cache = r);
620
621
        /* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see:
622
         * https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf
623
         * This table exists whenever the firmware knows ACPI and is hooked up to TPM2.
624
         * Note that in some cases, for example with EDK2 2025.2 with the default arm64 config, this ACPI
625
         * table is present even if TPM2 support is not enabled in the firmware. */
626
0
        if (access("/sys/firmware/acpi/tables/TPM2", F_OK) >= 0)
627
0
                return (cache = true);
628
0
        if (errno != ENOENT)
629
0
                log_debug_errno(errno, "Unable to test whether /sys/firmware/acpi/tables/TPM2 exists, assuming it doesn't: %m");
630
631
        /* As the last try, check if the EFI firmware provides the EFI_TCG2_FINAL_EVENTS_TABLE
632
         * stored in EFI configuration table, see:
633
         *
634
         * https://trustedcomputinggroup.org/wp-content/uploads/EFI-Protocol-Specification-rev13-160330final.pdf */
635
0
        if (access("/sys/kernel/security/tpm0/binary_bios_measurements", F_OK) >= 0) {
636
0
                _cleanup_free_ char *major = NULL;
637
638
                /* The EFI table might exist for TPM 1.2 as well, hence let's check explicitly which TPM version we are looking at here. */
639
0
                r = read_virtual_file("/sys/class/tpm/tpm0/tpm_version_major", SIZE_MAX, &major, /* ret_size= */ NULL);
640
0
                if (r >= 0)
641
0
                        return (cache = streq(strstrip(major), "2"));
642
643
0
                log_debug_errno(r, "Unable to read /sys/class/tpm/tpm0/tpm_version_major, assuming TPM does not qualify as TPM2: %m");
644
645
0
        } else if (errno != ENOENT)
646
0
                  log_debug_errno(errno, "Unable to test whether /sys/kernel/security/tpm0/binary_bios_measurements exists, assuming it doesn't: %m");
647
648
0
        return (cache = false);
649
#else
650
        return -EOPNOTSUPP;
651
#endif
652
0
}
653
654
0
sd_id128_t efi_guid_to_id128(const void *guid) {
655
0
        EFI_GUID uuid;
656
0
        sd_id128_t id128;
657
658
        /* The input pointer is not guaranteed to be aligned (e.g. when pointing into a serialized EFI
659
         * variable buffer), so copy into a properly aligned local first. */
660
0
        memcpy(&uuid, ASSERT_PTR(guid), sizeof(uuid));
661
662
0
        id128.bytes[0] = (uuid.Data1 >> 24) & 0xff;
663
0
        id128.bytes[1] = (uuid.Data1 >> 16) & 0xff;
664
0
        id128.bytes[2] = (uuid.Data1 >> 8) & 0xff;
665
0
        id128.bytes[3] = uuid.Data1 & 0xff;
666
667
0
        id128.bytes[4] = (uuid.Data2 >> 8) & 0xff;
668
0
        id128.bytes[5] = uuid.Data2 & 0xff;
669
670
0
        id128.bytes[6] = (uuid.Data3 >> 8) & 0xff;
671
0
        id128.bytes[7] = uuid.Data3 & 0xff;
672
673
0
        memcpy(&id128.bytes[8], uuid.Data4, sizeof(uuid.Data4));
674
675
0
        return id128;
676
0
}
677
678
0
void efi_id128_to_guid(sd_id128_t id, void *ret_guid) {
679
0
        assert(ret_guid);
680
681
0
        EFI_GUID uuid = {
682
0
                .Data1 = (uint32_t) id.bytes[0] << 24 | (uint32_t) id.bytes[1] << 16 | (uint32_t) id.bytes[2] << 8 | id.bytes[3],
683
0
                .Data2 = (uint16_t) id.bytes[4] << 8 | id.bytes[5],
684
0
                .Data3 = (uint16_t) id.bytes[6] << 8 | id.bytes[7],
685
0
        };
686
0
        memcpy(uuid.Data4, id.bytes+8, sizeof(uuid.Data4));
687
0
        memcpy(ret_guid, &uuid, sizeof(uuid));
688
0
}