]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/pcrlock/pcrlock.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / src / pcrlock / pcrlock.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <getopt.h>
4 #include <math.h>
5 #include <openssl/evp.h>
6 #include <sys/file.h>
7
8 #include "sd-device.h"
9
10 #include "ask-password-api.h"
11 #include "blockdev-util.h"
12 #include "build.h"
13 #include "chase.h"
14 #include "color-util.h"
15 #include "conf-files.h"
16 #include "efi-api.h"
17 #include "env-util.h"
18 #include "escape.h"
19 #include "fd-util.h"
20 #include "fileio.h"
21 #include "format-table.h"
22 #include "format-util.h"
23 #include "fs-util.h"
24 #include "gpt.h"
25 #include "hash-funcs.h"
26 #include "hexdecoct.h"
27 #include "initrd-util.h"
28 #include "main-func.h"
29 #include "mkdir-label.h"
30 #include "openssl-util.h"
31 #include "ordered-set.h"
32 #include "parse-argument.h"
33 #include "parse-util.h"
34 #include "path-util.h"
35 #include "pcrextend-util.h"
36 #include "pcrlock-firmware.h"
37 #include "pehash.h"
38 #include "pretty-print.h"
39 #include "proc-cmdline.h"
40 #include "random-util.h"
41 #include "recovery-key.h"
42 #include "sort-util.h"
43 #include "terminal-util.h"
44 #include "tpm2-util.h"
45 #include "unaligned.h"
46 #include "unit-name.h"
47 #include "utf8.h"
48 #include "verbs.h"
49
50 static PagerFlags arg_pager_flags = 0;
51 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF|JSON_FORMAT_NEWLINE;
52 static char **arg_components = NULL;
53 static uint32_t arg_pcr_mask = 0;
54 static char *arg_pcrlock_path = NULL;
55 static bool arg_pcrlock_auto = true;
56 static bool arg_raw_description = false;
57 static char *arg_location_start = NULL;
58 static char *arg_location_end = NULL;
59 static TPM2_HANDLE arg_nv_index = 0;
60 static bool arg_recovery_pin = false;
61 static char *arg_policy_path = NULL;
62 static bool arg_force = false;
63
64 STATIC_DESTRUCTOR_REGISTER(arg_components, strv_freep);
65 STATIC_DESTRUCTOR_REGISTER(arg_pcrlock_path, freep);
66 STATIC_DESTRUCTOR_REGISTER(arg_location_start, freep);
67 STATIC_DESTRUCTOR_REGISTER(arg_location_end, freep);
68 STATIC_DESTRUCTOR_REGISTER(arg_policy_path, freep);
69
70 #define PCRLOCK_SECUREBOOT_POLICY_PATH "/var/lib/pcrlock.d/240-secureboot-policy.pcrlock.d/generated.pcrlock"
71 #define PCRLOCK_FIRMWARE_CODE_EARLY_PATH "/var/lib/pcrlock.d/250-firmware-code-early.pcrlock.d/generated.pcrlock"
72 #define PCRLOCK_FIRMWARE_CONFIG_EARLY_PATH "/var/lib/pcrlock.d/250-firmware-config-early.pcrlock.d/generated.pcrlock"
73 #define PCRLOCK_FIRMWARE_CODE_LATE_PATH "/var/lib/pcrlock.d/550-firmware-code-late.pcrlock.d/generated.pcrlock"
74 #define PCRLOCK_FIRMWARE_CONFIG_LATE_PATH "/var/lib/pcrlock.d/550-firmware-config-late.pcrlock.d/generated.pcrlock"
75 #define PCRLOCK_GPT_PATH "/var/lib/pcrlock.d/600-gpt.pcrlock.d/generated.pcrlock"
76 #define PCRLOCK_SECUREBOOT_AUTHORITY_PATH "/var/lib/pcrlock.d/620-secureboot-authority.pcrlock.d/generated.pcrlock"
77 #define PCRLOCK_KERNEL_CMDLINE_PATH "/var/lib/pcrlock.d/710-kernel-cmdline.pcrlock/generated.pcrlock"
78 #define PCRLOCK_KERNEL_INITRD_PATH "/var/lib/pcrlock.d/720-kernel-initrd.pcrlock/generated.pcrlock"
79 #define PCRLOCK_MACHINE_ID_PATH "/var/lib/pcrlock.d/820-machine-id.pcrlock"
80 #define PCRLOCK_ROOT_FILE_SYSTEM_PATH "/var/lib/pcrlock.d/830-root-file-system.pcrlock"
81 #define PCRLOCK_FILE_SYSTEM_PATH_PREFIX "/var/lib/pcrlock.d/840-file-system-"
82
83 /* The default set of PCRs to lock to */
84 #define DEFAULT_PCR_MASK \
85 ((UINT32_C(1) << TPM2_PCR_PLATFORM_CODE) | \
86 (UINT32_C(1) << TPM2_PCR_PLATFORM_CONFIG) | \
87 (UINT32_C(1) << TPM2_PCR_EXTERNAL_CODE) | \
88 (UINT32_C(1) << TPM2_PCR_EXTERNAL_CONFIG) | \
89 (UINT32_C(1) << TPM2_PCR_BOOT_LOADER_CODE) | \
90 (UINT32_C(1) << TPM2_PCR_BOOT_LOADER_CONFIG) | \
91 (UINT32_C(1) << TPM2_PCR_SECURE_BOOT_POLICY) | \
92 (UINT32_C(1) << TPM2_PCR_KERNEL_BOOT) | \
93 (UINT32_C(1) << TPM2_PCR_KERNEL_CONFIG) | \
94 (UINT32_C(1) << TPM2_PCR_SYSEXTS) | \
95 (UINT32_C(1) << TPM2_PCR_SHIM_POLICY) | \
96 (UINT32_C(1) << TPM2_PCR_SYSTEM_IDENTITY))
97
98 typedef struct EventLogRecordBank EventLogRecordBank;
99 typedef struct EventLogRecord EventLogRecord;
100 typedef struct EventLogRegisterBank EventLogRegisterBank;
101 typedef struct EventLogRegister EventLogRegister;
102 typedef struct EventLogComponentVariant EventLogComponentVariant;
103 typedef struct EventLogComponent EventLogComponent;
104 typedef struct EventLog EventLog;
105
106 struct EventLogRecordBank {
107 uint16_t algorithm;
108 TPM2B_DIGEST hash;
109 LIST_FIELDS(EventLogRecordBank, banks);
110 };
111
112 typedef enum EventPayloadValid {
113 EVENT_PAYLOAD_VALID_YES,
114 EVENT_PAYLOAD_VALID_NO,
115 EVENT_PAYLOAD_VALID_DONT_KNOW,
116 _EVENT_PAYLOAD_VALID_MAX,
117 _EVENT_PAYLOAD_VALID_INVALID = -EINVAL,
118 } EventPayloadValid;
119
120 struct EventLogRecord {
121 EventLog *event_log;
122 uint32_t pcr;
123
124 const char *source;
125 char *description;
126
127 /* Data for firmware events (i.e. "TCG PC Client Platform Firmware Profile Specification" events) */
128 uint32_t firmware_event_type;
129 void *firmware_payload;
130 size_t firmware_payload_size;
131
132 /* Data for userspace events (i.e. those generated by systemd in userspace */
133 Tpm2UserspaceEventType userspace_event_type;
134 JsonVariant *userspace_content;
135
136 /* Validation result for the event payload itself, if the record contains enough information to validate the hash */
137 EventPayloadValid event_payload_valid;
138
139 /* If this record matches an variant of one of our defined components */
140 EventLogComponentVariant **mapped;
141 size_t n_mapped;
142
143 /* If this record is part of an EventLogComponentVariant */
144 EventLogComponentVariant *owning_component_variant;
145
146 LIST_HEAD(EventLogRecordBank, banks);
147 };
148
149 #define EVENT_LOG_RECORD_IS_FIRMWARE(record) ((record)->firmware_event_type != UINT32_MAX)
150 #define EVENT_LOG_RECORD_IS_USERSPACE(record) ((record)->userspace_event_type >= 0)
151
152 struct EventLogRegisterBank {
153 TPM2B_DIGEST observed;
154 TPM2B_DIGEST calculated;
155 };
156
157 struct EventLogRegister {
158 char *color;
159 unsigned n_measurements;
160 bool fully_recognized; /* true if all measurements in this register have been recognized to match components */
161 EventLogRegisterBank *banks;
162 };
163
164 struct EventLogComponentVariant {
165 EventLogComponent *component;
166
167 char *id;
168 char *path;
169
170 EventLogRecord **records;
171 size_t n_records;
172 };
173
174 struct EventLogComponent {
175 char *id;
176
177 EventLogComponentVariant **variants;
178 size_t n_variants;
179 };
180
181 struct EventLog {
182 EventLogRecord **records;
183 size_t n_records;
184
185 uint16_t *algorithms;
186 size_t n_algorithms;
187 bool algorithms_locked; /* if algorithms where set explicitly by user, and we should not determine them automatically */
188
189 const EVP_MD **mds;
190
191 /* The hash algorithm which we focus on for matching up components */
192 uint16_t primary_algorithm;
193
194 uint8_t startup_locality;
195 bool startup_locality_found;
196
197 EventLogRegister registers[TPM2_PCRS_MAX];
198
199 EventLogComponent **components;
200 size_t n_components;
201
202 /* Number of components which we couldn't find in the event log */
203 size_t n_missing_components;
204
205 /* PCRs mask indicating all PCRs touched by unrecognized components */
206 uint32_t missing_component_pcrs;
207 };
208
209 static EventLogRecordBank *event_log_record_bank_free(EventLogRecordBank *bank) {
210 return mfree(bank);
211 }
212
213 DEFINE_TRIVIAL_CLEANUP_FUNC(EventLogRecordBank*, event_log_record_bank_free);
214
215 static EventLogRecord *event_log_record_free(EventLogRecord *record) {
216 EventLogRecordBank *bank;
217
218 if (!record)
219 return NULL;
220
221 free(record->description);
222 free(record->firmware_payload);
223 json_variant_unref(record->userspace_content);
224
225 while ((bank = LIST_POP(banks, record->banks)))
226 event_log_record_bank_free(bank);
227
228 free(record->mapped);
229
230 return mfree(record);
231 }
232
233 DEFINE_TRIVIAL_CLEANUP_FUNC(EventLogRecord*, event_log_record_free);
234
235 static void event_log_register_done(EventLog *el, EventLogRegister *reg) {
236 assert(reg);
237
238 free(reg->color);
239 free(reg->banks);
240 }
241
242 static EventLogComponentVariant* event_log_component_variant_free(EventLogComponentVariant *variant) {
243 if (!variant)
244 return NULL;
245
246 free(variant->id);
247 free(variant->path);
248
249 FOREACH_ARRAY(record, variant->records, variant->n_records)
250 event_log_record_free(*record);
251
252 free(variant->records);
253
254 return mfree(variant);
255 }
256
257 DEFINE_TRIVIAL_CLEANUP_FUNC(EventLogComponentVariant*, event_log_component_variant_free);
258
259 static EventLogComponent* event_log_component_free(EventLogComponent *component) {
260 if (!component)
261 return NULL;
262
263 FOREACH_ARRAY(variant, component->variants, component->n_variants)
264 event_log_component_variant_free(*variant);
265 free(component->variants);
266
267 free(component->id);
268
269 return mfree(component);
270 }
271
272 DEFINE_TRIVIAL_CLEANUP_FUNC(EventLogComponent*, event_log_component_free);
273
274 static EventLog* event_log_free(EventLog *el) {
275 if (!el)
276 return NULL;
277
278 FOREACH_ARRAY(p, el->registers, TPM2_PCRS_MAX)
279 event_log_register_done(el, p);
280
281 FOREACH_ARRAY(rr, el->records, el->n_records)
282 event_log_record_free(*rr);
283 free(el->records);
284
285 FOREACH_ARRAY(c, el->components, el->n_components)
286 event_log_component_free(*c);
287 free(el->components);
288
289 free(el->algorithms);
290 free(el->mds);
291
292 return mfree(el);
293 }
294
295 DEFINE_TRIVIAL_CLEANUP_FUNC(EventLog*, event_log_free);
296
297 static EventLogRecord* event_log_record_new(EventLog *el) {
298 EventLogRecord *record;
299
300 record = new(EventLogRecord, 1);
301 if (!record)
302 return NULL;
303
304 *record = (EventLogRecord) {
305 .event_log = el,
306 .firmware_event_type = UINT32_MAX,
307 .userspace_event_type = _TPM2_USERSPACE_EVENT_TYPE_INVALID,
308 .event_payload_valid = _EVENT_PAYLOAD_VALID_INVALID,
309 };
310
311 return record;
312 }
313
314 static int event_log_add_record(
315 EventLog *el,
316 EventLogRecord **ret) {
317
318 _cleanup_(event_log_record_freep) EventLogRecord *record = NULL;
319
320 assert(el);
321
322 if (!GREEDY_REALLOC(el->records, el->n_records+1))
323 return -ENOMEM;
324
325 record = event_log_record_new(el);
326 if (!record)
327 return -ENOMEM;
328
329 el->records[el->n_records++] = record;
330
331 if (ret)
332 *ret = record;
333
334 TAKE_PTR(record);
335
336 return 0;
337 }
338
339 static int event_log_add_algorithm(EventLog *el, uint16_t alg) {
340 assert(el);
341
342 if (el->algorithms_locked) /* algorithms configured via env var, don't add any further automatically */
343 return 0;
344
345 if (typesafe_bsearch(&alg, el->algorithms, el->n_algorithms, cmp_uint16))
346 return 0;
347
348 if (!GREEDY_REALLOC(el->algorithms, el->n_algorithms+1))
349 return -ENOMEM;
350
351 el->algorithms[el->n_algorithms++] = alg;
352
353 typesafe_qsort(el->algorithms, el->n_algorithms, cmp_uint16);
354
355 return 1;
356 }
357
358 static int event_log_add_algorithms_from_environment(EventLog *el) {
359 const char *e;
360 int r;
361
362 assert(el);
363
364 e = secure_getenv("SYSTEMD_TPM2_HASH_ALGORITHMS");
365 if (!e)
366 return 0;
367
368 for (;;) {
369 _cleanup_free_ char *word = NULL;
370
371 r = extract_first_word(&e, &word, ":", 0);
372 if (r < 0)
373 return r;
374 if (r == 0)
375 break;
376
377 r = tpm2_hash_alg_from_string(word);
378 if (r < 0)
379 return log_error_errno(r, "Unknown hash algorithm '%s'.", word);
380
381 r = event_log_add_algorithm(el, r);
382 if (r < 0)
383 return log_error_errno(r, "Failed to add hash algorithm '%s'.", word);
384 }
385
386 if (el->n_algorithms > 0)
387 el->algorithms_locked = true;
388
389 return 0;
390 }
391
392 static EventLogRecordBank *event_log_record_find_bank(
393 const EventLogRecord *record,
394 uint16_t alg) {
395
396 assert(record);
397
398 LIST_FOREACH(banks, i, record->banks)
399 if (i->algorithm == alg)
400 return i;
401
402 return NULL;
403 }
404
405 static int event_log_record_add_bank(
406 EventLogRecord *record,
407 uint16_t algorithm,
408 const void *hash,
409 size_t hash_size,
410 EventLogRecordBank **ret) {
411
412 _cleanup_(event_log_record_bank_freep) EventLogRecordBank *bank = NULL;
413 _cleanup_free_ void *h = NULL;
414
415 assert(record);
416 assert(hash || hash_size == 0);
417
418 if (event_log_record_find_bank(record, algorithm))
419 return -EEXIST;
420
421 if (hash_size > sizeof_field(TPM2B_DIGEST, buffer))
422 return -E2BIG;
423
424 h = memdup(hash, hash_size);
425 if (!h)
426 return -ENOMEM;
427
428 bank = new(EventLogRecordBank, 1);
429 if (!bank)
430 return -ENOMEM;
431
432 *bank = (EventLogRecordBank) {
433 .algorithm = algorithm,
434 .hash = TPM2B_DIGEST_MAKE(hash, hash_size),
435 };
436
437 LIST_PREPEND(banks, record->banks, bank);
438
439 if (ret)
440 *ret = bank;
441
442 TAKE_PTR(bank);
443
444 return 0;
445 }
446
447 static bool event_log_record_is_stub(EventLogRecord *rec) {
448 assert(rec);
449
450 /* Recognizes the special EV_IPL events systemd-stub generates. Since EV_IPL can be used by almost
451 * anything, we'll check for the PCR values, to see if it's one of ours. */
452
453 if (rec->firmware_event_type != EV_IPL)
454 return false;
455
456 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
457 return false;
458
459 if (!IN_SET(rec->pcr,
460 TPM2_PCR_KERNEL_BOOT, /* 11 */
461 TPM2_PCR_KERNEL_CONFIG, /* 12 */
462 TPM2_PCR_SYSEXTS)) /* 13 */
463 return false;
464
465 return true;
466 }
467
468 static int event_log_record_parse_variable_data(
469 EventLogRecord *rec,
470 sd_id128_t *ret_variable_uuid,
471 char **ret_variable_name) {
472
473 _cleanup_free_ char16_t *p16 = NULL;
474 _cleanup_free_ char *p = NULL;
475
476 assert(rec);
477 assert(ret_variable_uuid);
478 assert(ret_variable_name);
479
480 if (rec->firmware_payload_size < sizeof(UEFI_VARIABLE_DATA))
481 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "EFI variable field too short.");
482
483 const UEFI_VARIABLE_DATA *vdata = rec->firmware_payload;
484
485 if (vdata->unicodeNameLength > (SIZE_MAX - offsetof(UEFI_VARIABLE_DATA, unicodeNameLength)) / 2)
486 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Unicode name length too large.");
487
488 size_t m = offsetof(UEFI_VARIABLE_DATA, unicodeName) + vdata->unicodeNameLength * 2;
489
490 if (vdata->variableDataLength > SIZE_MAX - m)
491 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Oversize EFI variable data size.");
492
493 if (rec->firmware_payload_size != m + vdata->variableDataLength)
494 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "EFI variable data has wrong size.");
495
496 p16 = memdup(vdata->unicodeName, vdata->unicodeNameLength * 2); /* Copy out, to align properly */
497 if (!p16)
498 return log_oom_debug();
499
500 p = utf16_to_utf8(p16, vdata->unicodeNameLength * 2);
501 if (!p)
502 return log_oom_debug();
503
504 if (!string_is_safe(p))
505 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Unsafe EFI variable string in record.");
506
507 *ret_variable_uuid = efi_guid_to_id128(vdata->variableName);
508 *ret_variable_name = TAKE_PTR(p);
509
510 return 0;
511 }
512
513 static int event_log_record_extract_firmware_description(EventLogRecord *rec) {
514 _cleanup_free_ char *fallback = NULL;
515 int r;
516
517 assert(rec);
518
519 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
520 return 0;
521
522 if (arg_raw_description)
523 goto catchall;
524
525 switch (rec->firmware_event_type) {
526
527 case EV_EFI_VARIABLE_DRIVER_CONFIG:
528 case EV_EFI_VARIABLE_BOOT:
529 case EV_EFI_VARIABLE_BOOT2:
530 case EV_EFI_VARIABLE_AUTHORITY: {
531 _cleanup_free_ char *p = NULL;
532 sd_id128_t uuid;
533
534 r = event_log_record_parse_variable_data(rec, &uuid, &p);
535 if (r == -ENOMEM)
536 return log_oom();
537 if (r < 0) {
538 log_warning_errno(r, "EFI variable data invalid, ignoring.");
539 goto invalid;
540 }
541
542 if (asprintf(&rec->description, "%s: %s-" SD_ID128_UUID_FORMAT_STR,
543 rec->firmware_event_type == EV_EFI_VARIABLE_AUTHORITY ? "Authority" : "Variable",
544 p,
545 SD_ID128_FORMAT_VAL(uuid)) < 0)
546 return log_oom();
547
548 return 1;
549 }
550
551 case EV_SEPARATOR: {
552 if (rec->firmware_payload_size != sizeof(uint32_t)) {
553 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "EFI separator field has wrong size, ignoring.");
554 goto invalid;
555 }
556
557 uint32_t val = unaligned_read_ne32(rec->firmware_payload);
558
559 switch (val) {
560
561 case 0:
562 case UINT32_C(0xffffffff):
563 (void) asprintf(&rec->description, "Separator: Success (0x%02" PRIx32 ")", val);
564 break;
565
566 case 1:
567 rec->description = strdup("Separator: Error (0x01)");
568 break;
569
570 default:
571 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Unexpected separator payload %" PRIu32 ".", val);
572 goto invalid;
573 }
574
575 if (!rec->description)
576 return log_oom();
577
578 return 1;
579 }
580
581 case EV_EFI_ACTION: {
582 _cleanup_free_ char *d = NULL;
583
584 r = make_cstring(rec->firmware_payload, rec->firmware_payload_size, MAKE_CSTRING_ALLOW_TRAILING_NUL, &d);
585 if (r < 0)
586 return log_error_errno(r, "Failed to make C string from EFI action string: %m");
587
588 if (!string_is_safe(d)) {
589 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Unsafe EFI action string in record, ignoring.");
590 goto invalid;
591 }
592
593 rec->description = strjoin("Action: ", d);
594 if (!rec->description)
595 return log_oom();
596 return 1;
597 }
598
599 case EV_EFI_GPT_EVENT: {
600 if (rec->firmware_payload_size < sizeof(GptHeader)) {
601 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "GPT measurement too short, ignoring.");
602 goto invalid;
603 }
604
605 const GptHeader *h = rec->firmware_payload;
606
607 if (!gpt_header_has_signature(h)) {
608 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "GPT measurement does not cover a GPT partition table header, ignoring.");
609 goto invalid;
610 }
611
612 if (asprintf(&rec->description, "GPT: disk " SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(efi_guid_to_id128(h->disk_guid))) < 0)
613 return log_oom();
614
615 return 1;
616 }
617
618 case EV_IPL: {
619 _cleanup_free_ char *d = NULL;
620
621 /* EV_IPL can be anything, only try to parse the description on PCRs we "own" */
622 if (!event_log_record_is_stub(rec))
623 break;
624
625 /* sd-stub always sets a description string as text for these */
626
627 d = utf16_to_utf8(rec->firmware_payload, rec->firmware_payload_size);
628 if (!d)
629 return log_oom();
630
631 if (string_has_cc(d, NULL)) {
632 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Unsafe EFI action string in record, ignoring.");
633 goto invalid;
634 }
635
636 rec->description = strjoin("String: ", d);
637 if (!rec->description)
638 return log_oom();
639
640 return 1;
641 }
642
643 case EV_EVENT_TAG: {
644 TCG_PCClientTaggedEvent *tag = rec->firmware_payload;
645 size_t left = rec->firmware_payload_size;
646
647 if (left == 0) {
648 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Empty tagged PC client event, ignoring.");
649 goto invalid;
650 }
651
652 for (;;) {
653 uint64_t m;
654
655 if (left < offsetof(TCG_PCClientTaggedEvent, taggedEventData)) {
656 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Tagged PC client event too short, ignoring.");
657 goto invalid;
658 }
659
660 m = offsetof(TCG_PCClientTaggedEvent, taggedEventData) + (uint64_t) tag->taggedEventDataSize;
661 if (left < m) {
662 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Tagged PC client event data too short, ignoring.");
663 goto invalid;
664 }
665
666 switch (tag->taggedEventID) {
667
668 /* Linux kernel's own measurements: */
669 case INITRD_EVENT_TAG_ID:
670 /* The tagged event payload is just a constant string, hence don't show it */
671 if (!strextend_with_separator(&rec->description, ", ", "Linux: initrd"))
672 return log_oom();
673 break;
674
675 case LOAD_OPTIONS_EVENT_TAG_ID:
676 /* As above. */
677 if (!strextend_with_separator(&rec->description, ", ", "Linux: kernel command line"))
678 return log_oom();
679 break;
680
681 /* systemd's measurements: */
682 case LOADER_CONF_EVENT_TAG_ID:
683 /* As above. */
684 if (!strextend_with_separator(&rec->description, ", ", "systemd-boot: loader.conf"))
685 return log_oom();
686 break;
687
688 case DEVICETREE_ADDON_EVENT_TAG_ID: {
689 _cleanup_free_ char *raw = NULL, *s = NULL;
690
691 raw = utf16_to_utf8((const char16_t*) tag->taggedEventData, tag->taggedEventDataSize);
692 if (!raw)
693 return log_oom();
694
695 s = cescape(raw);
696 if (!s)
697 return log_oom();
698
699 r = strextendf_with_separator(&rec->description, ", ", "systemd-stub: devicetree addon %s", s);
700 if (r < 0)
701 return log_error_errno(r, "Failed to format EV_EVENT_TAG description string: %m");
702 break;
703 }
704
705 default: {
706 _cleanup_free_ char *s = NULL;
707
708 s = cescape_length((char*) tag->taggedEventData, tag->taggedEventDataSize);
709 if (!s)
710 return log_oom();
711
712 r = strextendf_with_separator(&rec->description, ", ", "Tag 0x%" PRIx32 ": %s", tag->taggedEventID, s);
713 if (r < 0)
714 return log_error_errno(r, "Failed to format EV_EVENT_TAG description string: %m");
715
716 break;
717 }}
718
719 tag = (TCG_PCClientTaggedEvent*) ((uint8_t*) tag + m);
720 left -= m;
721
722 if (left == 0)
723 break;
724 }
725
726 return 1;
727 }
728
729 case EV_EFI_PLATFORM_FIRMWARE_BLOB: {
730 const UEFI_PLATFORM_FIRMWARE_BLOB *blob;
731 if (rec->firmware_payload_size != sizeof(UEFI_PLATFORM_FIRMWARE_BLOB)) {
732 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "EV_EFI_PLATFORM_FIRMWARE_BLOB of wrong size, ignoring.");
733 goto invalid;
734 }
735
736 blob = rec->firmware_payload;
737 if (asprintf(&rec->description, "Blob: %s @ 0x%" PRIx64, FORMAT_BYTES(blob->blobLength), blob->blobBase) < 0)
738 return log_oom();
739
740 return 1;
741 }
742
743 case EV_EFI_BOOT_SERVICES_APPLICATION:
744 case EV_EFI_BOOT_SERVICES_DRIVER:
745 case EV_EFI_RUNTIME_SERVICES_DRIVER: {
746 const UEFI_IMAGE_LOAD_EVENT *load;
747 _cleanup_free_ char *fn = NULL;
748 bool end = false;
749
750 if (rec->firmware_payload_size < offsetof(UEFI_IMAGE_LOAD_EVENT, devicePath)) {
751 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Device path too short, ignoring.");
752 goto invalid;
753 }
754
755 load = rec->firmware_payload;
756 if (load->lengthOfDevicePath !=
757 rec->firmware_payload_size - offsetof(UEFI_IMAGE_LOAD_EVENT, devicePath)) {
758 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Device path size does not match, ignoring.");
759 goto invalid;
760 }
761
762 const packed_EFI_DEVICE_PATH *dp = (const packed_EFI_DEVICE_PATH*) load->devicePath;
763 size_t left = load->lengthOfDevicePath;
764
765 for (;;) {
766 if (left == 0) {
767 if (!end) {
768 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Garbage after device path end, ignoring.");
769 goto invalid;
770 }
771
772 break;
773 }
774
775 if (end) {
776 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Garbage after device path end, ignoring.");
777 goto invalid;
778 }
779
780 if (left < offsetof(packed_EFI_DEVICE_PATH, path) || left < dp->length) {
781 log_warning_errno(SYNTHETIC_ERRNO(EBADMSG), "Device path element too short, ignoring.");
782 goto invalid;
783 }
784
785 if (dp->type == 4 && dp->subType == 4) {
786 /* Filename, store the last node of this type as description, it should contain the file name */
787
788 free(fn);
789 fn = utf16_to_utf8((void*) dp->path, dp->length - offsetof(packed_EFI_DEVICE_PATH, path));
790 if (!fn)
791 return log_oom();
792
793 } else if (dp->type == 0x7F && dp->subType == 0xFF)
794 /* End of Hardware Device Path */
795 end = true;
796 else
797 log_debug("Ignoring device path element type=0x%02x subtype=0x%02x", dp->type, dp->subType);
798
799 left -= dp->length;
800 dp = (packed_EFI_DEVICE_PATH*) ((uint8_t*) dp + dp->length);
801 }
802
803 if (fn) {
804 rec->description = strjoin("File: ", fn);
805 if (!rec->description)
806 return log_oom();
807
808 return 1;
809 }
810
811 break;
812 }}
813
814 catchall:
815 /* Catchall: show binary data */
816 fallback = cescape_length(rec->firmware_payload, rec->firmware_payload_size);
817 if (!fallback)
818 return log_oom();
819
820 rec->description = strjoin("Raw: ", fallback);
821 if (!rec->description)
822 return log_oom();
823 return 1;
824
825
826 invalid:
827 /* Mark the payload as invalid, so that we do not bother parsing/validating it any further */
828 rec->event_payload_valid = EVENT_PAYLOAD_VALID_NO;
829 return 0;
830 }
831
832 static int event_log_add_algorithms_from_record(EventLog *el, EventLogRecord *record) {
833 int r;
834
835 assert(el);
836 assert(record);
837
838 if (el->algorithms_locked)
839 return 0;
840
841 LIST_FOREACH(banks, i, record->banks) {
842 r = event_log_add_algorithm(el, i->algorithm);
843 if (r < 0)
844 return r;
845 }
846
847 return 0;
848 }
849
850 static int event_log_load_firmware(EventLog *el) {
851 const TCG_EfiSpecIdEventAlgorithmSize *algorithms;
852 size_t bufsize = 0, n_algorithms = 0, left = 0;
853 _cleanup_free_ void *buf = NULL;
854 const TCG_PCR_EVENT2 *event;
855 const char *path;
856 int r;
857
858 assert(el);
859
860 path = tpm2_firmware_log_path();
861
862 r = read_full_file(path, (char**) &buf, &bufsize);
863 if (r < 0)
864 return log_error_errno(r, "Failed to open TPM2 event log '%s': %m", path);
865
866 if (bufsize == 0) {
867 /* Sometimes it's useful to invoke things with SYSTEMD_MEASURE_LOG_FIRMWARE=/dev/null, let's allow that, and proceed */
868 log_warning("Empty firmware event log file, not loading.");
869 return 0;
870 }
871
872 r = validate_firmware_header(buf, bufsize, &algorithms, &n_algorithms, &event, &left);
873 if (r < 0)
874 return r;
875
876 for (const TCG_PCR_EVENT2 *next_event = NULL;; event = next_event) {
877 EventLogRecord *record = NULL;
878 const void *payload;
879 size_t payload_size;
880
881 r = validate_firmware_event(
882 event,
883 left,
884 algorithms,
885 n_algorithms,
886 &next_event,
887 &left,
888 &payload,
889 &payload_size);
890 if (r < 0)
891 return r;
892 if (r == 0)
893 break;
894
895 if (event->eventType == EV_NO_ACTION &&
896 event->pcrIndex == 0 &&
897 payload_size == 17 &&
898 memcmp(payload, "StartupLocality", sizeof("StartupLocality")) == 0) {
899 if (el->startup_locality_found)
900 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "StartupLocality event found twice!");
901
902 el->startup_locality = ((const uint8_t*) payload)[sizeof("StartupLocality")];
903 el->startup_locality_found = true;
904 log_debug("Found StartupLocality event: %u", el->startup_locality);
905 continue;
906 }
907
908 if (event->eventType == EV_NO_ACTION) { /* Ignore pseudo events, that don't result in a measurement */
909 log_debug("Skipping NO_ACTION event.");
910 continue;
911 }
912
913 r = event_log_add_record(el, &record);
914 if (r < 0)
915 return log_error_errno(r, "Failed to add record to event log: %m");
916
917 record->pcr = event->pcrIndex;
918 record->source = path;
919 record->firmware_event_type = event->eventType;
920 record->firmware_payload = memdup(payload, payload_size);
921 if (!record->firmware_payload)
922 return log_oom();
923 record->firmware_payload_size = payload_size;
924
925 const void *ha, *ha_next = NULL;
926 ha = (const uint8_t*) event + offsetof(TCG_PCR_EVENT2, digests.digests);
927 assert(event->digests.count == n_algorithms);
928
929 for (size_t i = 0; i < n_algorithms; i++, ha = ha_next) {
930 ha_next = (const uint8_t*) ha + offsetof(TPMT_HA, digest) + algorithms[i].digestSize;
931
932 /* The TPMT_HA is not aligned in the record, hence read the hashAlg field via an unaligned read */
933 assert_cc(__builtin_types_compatible_p(uint16_t, typeof(TPMI_ALG_HASH)));
934 uint16_t hash_alg = unaligned_read_ne16((const uint8_t*) ha + offsetof(TPMT_HA, hashAlg));
935
936 if (hash_alg != algorithms[i].algorithmId)
937 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Hash algorithms in event log record don't match log.");
938
939 if (!tpm2_hash_alg_to_string(algorithms[i].algorithmId))
940 continue;
941
942 r = event_log_record_add_bank(
943 record,
944 algorithms[i].algorithmId,
945 (const uint8_t*) ha + offsetof(TPMT_HA, digest),
946 algorithms[i].digestSize,
947 /* ret= */ NULL);
948 if (r < 0)
949 return log_error_errno(r, "Failed to add bank to event log record: %m");
950 }
951
952 /* Try to extract a descriptive text */
953 r = event_log_record_extract_firmware_description(record);
954 if (r < 0)
955 return r;
956
957 r = event_log_add_algorithms_from_record(el, record);
958 if (r < 0)
959 return r;
960 }
961
962 return 0;
963 }
964
965 static int event_log_record_parse_json(EventLogRecord *record, JsonVariant *j) {
966 const char *rectype = NULL;
967 JsonVariant *x, *k;
968 uint64_t u;
969 int r;
970
971 assert(record);
972 assert(j);
973
974 if (!json_variant_is_object(j))
975 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "record object is not an object.");
976
977 x = json_variant_by_key(j, "pcr");
978 if (!x)
979 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'pcr' field missing from TPM measurement log file entry.");
980 if (!json_variant_is_unsigned(x))
981 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'pcr' field is not an integer.");
982
983 u = json_variant_unsigned(x);
984 if (u >= TPM2_PCRS_MAX)
985 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'pcr' field is out of range.");
986 record->pcr = json_variant_unsigned(x);
987
988 x = json_variant_by_key(j, "digests");
989 if (!x)
990 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'digests' field missing from TPM measurement log file entry.");
991 if (!json_variant_is_array(x))
992 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'digests' field is not an array.");
993
994 JSON_VARIANT_ARRAY_FOREACH(k, x) {
995 _cleanup_free_ void *hash = NULL;
996 size_t hash_size;
997 JsonVariant *a, *h;
998 int na;
999
1000 a = json_variant_by_key(k, "hashAlg");
1001 if (!a)
1002 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'digests' field element lacks 'hashAlg' field.");
1003 if (!json_variant_is_string(a))
1004 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'hashAlg' field is not a string.");
1005
1006 na = tpm2_hash_alg_from_string(json_variant_string(a));
1007 if (na < 0) {
1008 log_debug_errno(na, "Unsupported hash '%s' in userspace event log, ignoring: %m", json_variant_string(a));
1009 continue;
1010 }
1011
1012 h = json_variant_by_key(k, "digest");
1013 if (!h)
1014 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'digests' field lacks 'digest' field");
1015
1016 r = json_variant_unhex(h, &hash, &hash_size);
1017 if (r < 0)
1018 return log_error_errno(r, "Failed to decode digest: %m");
1019
1020 r = event_log_record_add_bank(
1021 record,
1022 na,
1023 hash,
1024 hash_size,
1025 /* ret= */ NULL);
1026 if (r < 0)
1027 return log_error_errno(r, "Failed to add bank to event log record: %m");
1028 }
1029
1030 x = json_variant_by_key(j, "content_type");
1031 if (!x)
1032 log_debug("'content_type' missing from TPM measurement log file entry, ignoring.");
1033 else {
1034 if (!json_variant_is_string(x))
1035 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'content_type' field is not a string.");
1036
1037 rectype = json_variant_string(x);
1038 }
1039
1040 if (streq_ptr(rectype, "systemd")) {
1041 JsonVariant *y;
1042
1043 x = json_variant_by_key(j, "content");
1044 if (!x)
1045 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'content' field missing from TPM measurement log file entry.");
1046 if (!json_variant_is_object(x))
1047 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'content' sub-object is not an object.");
1048
1049 y = json_variant_by_key(x, "string");
1050 if (y) {
1051 if (!json_variant_is_string(y))
1052 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'string' field is not a string.");
1053
1054 r = free_and_strdup_warn(&record->description, json_variant_string(y));
1055 if (r < 0)
1056 return r;
1057 }
1058
1059 y = json_variant_by_key(x, "eventType");
1060 if (y) {
1061 if (!json_variant_is_string(y))
1062 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'eventType' field is not a string.");
1063
1064 record->userspace_event_type = tpm2_userspace_event_type_from_string(json_variant_string(y));
1065 if (record->userspace_event_type < 0)
1066 log_debug_errno(record->userspace_event_type, "Unknown userspace event type '%s', ignoring.", json_variant_string(y));
1067 }
1068
1069 json_variant_unref(record->userspace_content);
1070 record->userspace_content = json_variant_ref(x);
1071 }
1072
1073 return 0;
1074 }
1075
1076 static int event_log_load_userspace(EventLog *el) {
1077 _cleanup_fclose_ FILE *f = NULL;
1078 _cleanup_free_ char *b = NULL;
1079 bool beginning = true;
1080 const char *path;
1081 size_t bn = 0;
1082 int r;
1083
1084 assert(el);
1085
1086 path = tpm2_userspace_log_path();
1087
1088 f = fopen(path, "re");
1089 if (!f) {
1090 if (errno != ENOENT)
1091 return log_error_errno(errno, "Failed to open userspace TPM measurement log file: %m");
1092
1093 return 0;
1094 }
1095
1096 if (flock(fileno(f), LOCK_SH) < 0)
1097 return log_error_errno(errno, "Failed to lock userspace TPM measurement log file: %m");
1098
1099 for (;;) {
1100 _cleanup_(json_variant_unrefp) JsonVariant *j = NULL;
1101 EventLogRecord *record;
1102 int ch;
1103
1104 ch = fgetc(f);
1105 if (ch == EOF) {
1106 if (ferror(f))
1107 return log_error_errno(errno, "Failed to read local TPM measurement log file: %m");
1108
1109 if (beginning)
1110 break;
1111 } else if (ch != 0x1EU) {
1112 if (!GREEDY_REALLOC(b, bn + 2))
1113 return log_oom();
1114
1115 b[bn++] = (char) ch;
1116 continue;
1117 }
1118
1119 if (beginning) {
1120 beginning = false;
1121 continue;
1122 }
1123
1124 if (!GREEDY_REALLOC(b, bn + 1))
1125 return log_oom();
1126
1127 b[bn] = 0; /* Turn it into a string */
1128
1129 if (memchr(b, 0, bn)) {
1130 log_warning("Found record with embedded NUL byte, skipping.");
1131 continue;
1132 }
1133
1134 r = json_parse(b, 0, &j, NULL, NULL);
1135 if (r < 0)
1136 return log_error_errno(r, "Failed to parse local TPM measurement log file: %m");
1137
1138 r = event_log_add_record(el, &record);
1139 if (r < 0)
1140 return log_error_errno(r, "Failed to add record to event log: %m");
1141
1142 record->source = path;
1143
1144 r = event_log_record_parse_json(record, j);
1145 if (r < 0)
1146 return r;
1147
1148 r = event_log_add_algorithms_from_record(el, record);
1149 if (r < 0)
1150 return r;
1151
1152 if (ch == EOF)
1153 break;
1154
1155 b = mfree(b);
1156 bn = 0;
1157 }
1158
1159 return 0;
1160 }
1161
1162 static EventLog *event_log_new(void) {
1163 _cleanup_(event_log_freep) EventLog *el = NULL;
1164
1165 el = new(EventLog, 1);
1166 if (!el)
1167 return NULL;
1168
1169 *el = (EventLog) {
1170 .primary_algorithm = UINT16_MAX,
1171 };
1172
1173 return TAKE_PTR(el);
1174 }
1175
1176 static int event_log_load(EventLog *el) {
1177 int r;
1178
1179 assert(el);
1180
1181 r = event_log_load_firmware(el);
1182 if (r < 0)
1183 return r;
1184
1185 r = event_log_load_userspace(el);
1186 if (r < 0)
1187 return r;
1188
1189 return 0;
1190 }
1191
1192 static int event_log_read_pcrs(EventLog *el) {
1193 _cleanup_(tpm2_context_unrefp) Tpm2Context *tc = NULL;
1194 int r;
1195
1196 assert(el);
1197
1198 r = tpm2_context_new(NULL, &tc);
1199 if (r < 0)
1200 return r;
1201
1202 FOREACH_ARRAY(rr, el->registers, TPM2_PCRS_MAX) {
1203 if (rr->banks)
1204 continue;
1205
1206 rr->banks = new0(EventLogRegisterBank, el->n_algorithms);
1207 if (!rr->banks)
1208 return log_oom();
1209 }
1210
1211 for (size_t a = 0; a < el->n_algorithms; a++) {
1212 _cleanup_free_ Tpm2PCRValue *pcr_values = NULL;
1213 size_t n_pcr_values;
1214 TPML_PCR_SELECTION selection;
1215
1216 tpm2_tpml_pcr_selection_from_mask(TPM2_PCRS_MASK, el->algorithms[a], &selection);
1217 r = tpm2_pcr_read(tc, &selection, &pcr_values, &n_pcr_values);
1218 if (r < 0)
1219 return r;
1220
1221 FOREACH_ARRAY(v, pcr_values, n_pcr_values) {
1222 assert(v->hash == el->algorithms[a]);
1223 el->registers[v->index].banks[a].observed = v->value;
1224 }
1225 }
1226
1227 return 0;
1228 }
1229
1230 static void event_log_initial_pcr_state(EventLog *el, uint32_t pcr, size_t size, TPM2B_DIGEST *ret) {
1231 assert(el);
1232 assert(pcr < TPM2_PCRS_MAX);
1233 assert(size > 0);
1234 assert(size <= sizeof_field(TPM2B_DIGEST, buffer));
1235 assert(ret);
1236
1237 ret->size = size;
1238
1239 switch (pcr) {
1240
1241 case 0:
1242 memzero(ret->buffer, ret->size-1);
1243 ((uint8_t*) ret->buffer)[ret->size-1] = el->startup_locality_found ? el->startup_locality : 0;
1244 break;
1245
1246 case 1 ... 16:
1247 case 23:
1248 memzero(ret->buffer, ret->size);
1249 break;
1250
1251 case 17 ... 22:
1252 memset(ret->buffer, 0xffu, ret->size);
1253 break;
1254
1255 default:
1256 assert_not_reached();
1257 }
1258 }
1259
1260 static int event_log_calculate_pcrs(EventLog *el) {
1261 assert(el);
1262
1263 /* Iterates through the event log an calculates the expected hash values based on all listed records */
1264
1265 assert(!el->mds);
1266 el->mds = new(const EVP_MD*, el->n_algorithms);
1267 if (!el->mds)
1268 return log_oom();
1269
1270 for (size_t i = 0; i < el->n_algorithms; i++) {
1271 const EVP_MD *md;
1272 const char *a;
1273
1274 assert_se(a = tpm2_hash_alg_to_string(el->algorithms[i]));
1275 assert_se(md = EVP_get_digestbyname(a));
1276
1277 el->mds[i] = md;
1278 }
1279
1280 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++)
1281 for (size_t i = 0; i < el->n_algorithms; i++) {
1282 EventLogRegisterBank *b = el->registers[pcr].banks + i;
1283 event_log_initial_pcr_state(el, pcr, EVP_MD_size(el->mds[i]), &b->calculated);
1284 }
1285
1286 FOREACH_ARRAY(rr, el->records, el->n_records) {
1287 EventLogRegister *reg = el->registers + (*rr)->pcr;
1288
1289 for (size_t i = 0; i < el->n_algorithms; i++) {
1290 const char *n = tpm2_hash_alg_to_string(el->algorithms[i]);
1291 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *mc = NULL;
1292 EventLogRegisterBank *reg_b;
1293 EventLogRecordBank *rec_b;
1294 unsigned sz;
1295
1296 rec_b = event_log_record_find_bank(*rr, el->algorithms[i]);
1297 if (!rec_b) {
1298 log_warning_errno(SYNTHETIC_ERRNO(ENXIO), "Record with missing bank '%s', ignoring.", n);
1299 continue;
1300 }
1301
1302 reg_b = reg->banks + i;
1303
1304 mc = EVP_MD_CTX_new();
1305 if (!mc)
1306 return log_oom();
1307
1308 if (EVP_DigestInit_ex(mc, el->mds[i], NULL) != 1)
1309 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize %s message digest context.", n);
1310
1311 if (EVP_DigestUpdate(mc, reg_b->calculated.buffer, reg_b->calculated.size) != 1)
1312 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to run digest.");
1313
1314 if (EVP_DigestUpdate(mc, rec_b->hash.buffer, rec_b->hash.size) != 1)
1315 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to run digest.");
1316
1317 if (EVP_DigestFinal_ex(mc, reg_b->calculated.buffer, &sz) != 1)
1318 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to finalize hash context.");
1319
1320 assert(sz == reg_b->calculated.size);
1321 }
1322
1323 reg->n_measurements++;
1324 }
1325
1326 return 0;
1327 }
1328
1329 static int event_log_record_validate_hash_firmware(
1330 EventLogRecord *record,
1331 EventLogRecordBank *bank,
1332 const EVP_MD *md) {
1333
1334 _cleanup_free_ void *hdata_alternative = NULL;
1335 size_t hsz, hsz_alternative = 0;
1336 bool strict = false;
1337 const void *hdata;
1338
1339 assert(record);
1340 assert(bank);
1341 assert(md);
1342
1343 if (!EVENT_LOG_RECORD_IS_FIRMWARE(record))
1344 return 0;
1345
1346 switch (record->firmware_event_type) {
1347
1348 case EV_EFI_ACTION:
1349 case EV_EFI_GPT_EVENT:
1350 case EV_EFI_VARIABLE_BOOT2:
1351 case EV_EFI_VARIABLE_DRIVER_CONFIG:
1352 case EV_EFI_VARIABLE_AUTHORITY:
1353 case EV_SEPARATOR:
1354 case EV_S_CRTM_VERSION:
1355 /* Here the extended hash value is the hash value of the event payload. Note that
1356 * EV_PLATFORM_CONFIG_FLAGS (according to the TCG PC Client Platform Firmware Profile
1357 * Specification) is also supposed to be like this. But ovmf doesn't follow this requirement,
1358 * hence be lenient on that one, and don't include it here. */
1359 hdata = record->firmware_payload;
1360 hsz = record->firmware_payload_size;
1361 strict = true;
1362 break;
1363
1364 case EV_EFI_VARIABLE_BOOT: {
1365 const UEFI_VARIABLE_DATA *vdata = record->firmware_payload;
1366 size_t skip;
1367
1368 /* Here the extended hash value is the hash value of the variable data (i.e. excluding the
1369 * name).
1370 *
1371 * Note: we already checked the general validity of the UEFI_VARIABLE_DATA structure, hence
1372 * no need to do so again. */
1373
1374 assert(record->firmware_payload_size >= offsetof(UEFI_VARIABLE_DATA, unicodeName));
1375 skip = offsetof(UEFI_VARIABLE_DATA, unicodeName) + vdata->unicodeNameLength * 2;
1376
1377 assert(record->firmware_payload_size >= skip);
1378 hdata = (const uint8_t*) record->firmware_payload + skip;
1379 hsz = record->firmware_payload_size - skip;
1380 strict = true;
1381 break;
1382 }
1383
1384 case EV_IPL:
1385 if (event_log_record_is_stub(record)) {
1386 /* The PE section names have a descriptive string in UTF-16 in the payload, but the
1387 * hash is over the UTF-8 version (with suffixing 0), hence let's convert the payload
1388 * into that format here, and see if it checks out. */
1389 hdata_alternative = utf16_to_utf8(record->firmware_payload, record->firmware_payload_size);
1390 if (!hdata_alternative)
1391 return log_oom();
1392
1393 hsz_alternative = strlen(hdata_alternative) + 1; /* with NUL byte */
1394 }
1395
1396 _fallthrough_;
1397
1398 default:
1399 /* For the others check the data too, just in case. But usually this will not match, hence
1400 * only report if the checksum matches, but don't complain if it does not. */
1401 hdata = record->firmware_payload;
1402 hsz = record->firmware_payload_size;
1403 strict = false;
1404 break;
1405 }
1406
1407 int mdsz = EVP_MD_size(md);
1408 assert(mdsz > 0);
1409 assert((size_t) mdsz <= sizeof_field(TPM2B_DIGEST, buffer));
1410
1411 TPM2B_DIGEST payload_hash = {
1412 .size = mdsz,
1413 };
1414
1415 unsigned dsz = mdsz;
1416
1417 if (EVP_Digest(hdata, hsz, payload_hash.buffer, &dsz, md, NULL) != 1)
1418 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to calculate event payload hash.");
1419 assert(dsz == (unsigned) mdsz);
1420
1421 /* If this didn't match then let's try the alternative format here, if we have one, and check things then. */
1422 if (memcmp_nn(bank->hash.buffer, bank->hash.size, payload_hash.buffer, payload_hash.size) != 0 && hdata_alternative) {
1423 if (EVP_Digest(hdata_alternative, hsz_alternative, payload_hash.buffer, &dsz, md, NULL) != 1)
1424 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to calculate event payload hash.");
1425 assert(dsz == (unsigned) mdsz);
1426 }
1427
1428 if (memcmp_nn(bank->hash.buffer, bank->hash.size, payload_hash.buffer, payload_hash.size) != 0) {
1429 if (strict)
1430 record->event_payload_valid = EVENT_PAYLOAD_VALID_NO;
1431 else if (record->event_payload_valid != EVENT_PAYLOAD_VALID_NO)
1432 record->event_payload_valid = EVENT_PAYLOAD_VALID_DONT_KNOW;
1433 } else if (record->event_payload_valid < 0)
1434 record->event_payload_valid = EVENT_PAYLOAD_VALID_YES;
1435
1436 return 1;
1437 }
1438
1439 static int event_log_record_validate_hash_userspace(
1440 EventLogRecord *record,
1441 EventLogRecordBank *bank,
1442 const EVP_MD *md) {
1443
1444 _cleanup_free_ unsigned char *payload_hash = NULL;
1445 unsigned payload_hash_size;
1446 JsonVariant *js;
1447 const char *s;
1448 int mdsz;
1449
1450 assert(record);
1451 assert(bank);
1452 assert(md);
1453
1454 if (!EVENT_LOG_RECORD_IS_USERSPACE(record))
1455 return 0;
1456
1457 if (!record->userspace_content)
1458 return 0;
1459
1460 js = json_variant_by_key(record->userspace_content, "string");
1461 if (!js)
1462 return 0;
1463
1464 assert(json_variant_is_string(js));
1465 s = json_variant_string(js);
1466
1467 mdsz = EVP_MD_size(md);
1468 assert(mdsz > 0);
1469
1470 payload_hash_size = mdsz;
1471 payload_hash = malloc(payload_hash_size);
1472 if (!payload_hash)
1473 return log_oom();
1474
1475 if (EVP_Digest(s, strlen(s), payload_hash, &payload_hash_size, md, NULL) != 1)
1476 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to calculate event payload hash.");
1477
1478 assert((int) payload_hash_size == mdsz);
1479 if (memcmp_nn(bank->hash.buffer, bank->hash.size, payload_hash, payload_hash_size) != 0)
1480 record->event_payload_valid = EVENT_PAYLOAD_VALID_NO;
1481 else if (record->event_payload_valid < 0)
1482 record->event_payload_valid = EVENT_PAYLOAD_VALID_YES;
1483
1484 return 0;
1485 }
1486
1487 static int event_log_validate_record_hashes(EventLog *el) {
1488 int r;
1489
1490 assert(el);
1491
1492 /* For records which contain the full data to validate the hashes, do so. */
1493
1494 FOREACH_ARRAY(rr, el->records, el->n_records) {
1495
1496 LIST_FOREACH(banks, bank, (*rr)->banks) {
1497 const EVP_MD *md;
1498 const char *a;
1499
1500 assert_se(a = tpm2_hash_alg_to_string(bank->algorithm));
1501 assert_se(md = EVP_get_digestbyname(a));
1502
1503 r = event_log_record_validate_hash_firmware(*rr, bank, md);
1504 if (r < 0)
1505 return r;
1506
1507 r = event_log_record_validate_hash_userspace(*rr, bank, md);
1508 if (r < 0)
1509 return r;
1510 }
1511 }
1512
1513 return 0;
1514 }
1515
1516 static int event_log_component_cmp(EventLogComponent *const*a, EventLogComponent *const*b) {
1517 const EventLogComponent *x = ASSERT_PTR(*ASSERT_PTR(a)), *y = ASSERT_PTR(*ASSERT_PTR(b));
1518
1519 return strcmp(x->id, y->id);
1520 }
1521
1522 static EventLogComponent *event_log_find_component(EventLog *el, const char *id) {
1523 EventLogComponent k = {
1524 .id = (char*) id,
1525 };
1526 EventLogComponent *kk = &k, **found;
1527
1528 assert(el);
1529 assert(id);
1530
1531 found = typesafe_bsearch(
1532 &kk,
1533 el->components,
1534 el->n_components,
1535 event_log_component_cmp);
1536 if (!found)
1537 return NULL;
1538
1539 return *found;
1540 }
1541
1542 static int event_log_add_component(EventLog *el, const char *id, EventLogComponent **ret) {
1543 _cleanup_(event_log_component_freep) EventLogComponent *component = NULL;
1544 _cleanup_free_ char *id_copy = NULL;
1545 EventLogComponent *found;
1546
1547 assert(el);
1548 assert(ret);
1549
1550 found = event_log_find_component(el, id);
1551 if (found) {
1552 *ret = found;
1553 return 0;
1554 }
1555
1556 if (!GREEDY_REALLOC(el->components, el->n_components+1))
1557 return log_oom();
1558
1559 id_copy = strdup(id);
1560 if (!id_copy)
1561 return log_oom();
1562
1563 component = new(EventLogComponent, 1);
1564 if (!component)
1565 return log_oom();
1566
1567 *component = (EventLogComponent) {
1568 .id = TAKE_PTR(id_copy),
1569 };
1570
1571 if (ret)
1572 *ret = component;
1573
1574 el->components[el->n_components++] = TAKE_PTR(component);
1575 return 1;
1576 }
1577
1578 static int event_log_record_equal(const EventLogRecord *a, const EventLogRecord *b) {
1579 EventLogRecordBank *x, *y;
1580
1581 assert(a);
1582 assert(a->event_log);
1583 assert(b);
1584 assert(b->event_log);
1585 assert(a->event_log == b->event_log);
1586
1587 if (a->pcr != b->pcr)
1588 return false;
1589
1590 x = event_log_record_find_bank(a, a->event_log->primary_algorithm);
1591 y = event_log_record_find_bank(b, b->event_log->primary_algorithm);
1592 if (!x || !y)
1593 return false;
1594
1595 assert(x->algorithm == a->event_log->primary_algorithm);
1596 assert(y->algorithm == b->event_log->primary_algorithm);
1597
1598 return memcmp_nn(x->hash.buffer, x->hash.size, y->hash.buffer, y->hash.size) == 0;
1599 }
1600
1601 static int event_log_add_component_file(EventLog *el, EventLogComponent *component, const char *path) {
1602 _cleanup_(event_log_component_variant_freep) EventLogComponentVariant *variant = NULL;
1603 _cleanup_free_ char *fname = NULL, *id = NULL, *path_copy = NULL;
1604 _cleanup_(json_variant_unrefp) JsonVariant *j = NULL;
1605 JsonVariant *records;
1606 const char *e;
1607 int r;
1608
1609 assert(el);
1610
1611 r = path_extract_filename(path, &fname);
1612 if (r < 0)
1613 return log_error_errno(r, "Failed to extract basename from path %s: %m", path);
1614
1615 e = endswith(fname, ".pcrlock");
1616 if (!e)
1617 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad suffix: %s", fname);
1618
1619 id = strndup(fname, e - fname);
1620 if (!id)
1621 return log_oom();
1622
1623 if (!component) {
1624 r = event_log_add_component(el, id, &component);
1625 if (r < 0)
1626 return r;
1627 }
1628
1629 if (!GREEDY_REALLOC(component->variants, component->n_variants+1))
1630 return log_oom();
1631
1632 r = json_parse_file(
1633 /* f= */ NULL,
1634 path,
1635 /* flags= */ 0,
1636 &j,
1637 /* ret_line= */ NULL,
1638 /* ret_column= */ NULL);
1639 if (r < 0) {
1640 log_warning_errno(r, "Failed to parse component file %s, ignoring: %m", path);
1641 return 0;
1642 }
1643
1644 if (!json_variant_is_object(j)) {
1645 log_warning_errno(r, "Component file %s does not contain JSON object, ignoring.", path);
1646 return 0;
1647 }
1648
1649 path_copy = strdup(path);
1650 if (!path_copy)
1651 return log_oom();
1652
1653 variant = new(EventLogComponentVariant, 1);
1654 if (!variant)
1655 return log_oom();
1656
1657 *variant = (EventLogComponentVariant) {
1658 .component = component,
1659 .path = TAKE_PTR(path_copy),
1660 .id = TAKE_PTR(id),
1661 };
1662
1663 records = json_variant_by_key(j, "records");
1664 if (records) {
1665 JsonVariant *rj;
1666
1667 if (!json_variant_is_array(records)) {
1668 log_warning_errno(r, "Component records field of file %s is not an array, ignoring.", path);
1669 return 0;
1670 }
1671
1672 JSON_VARIANT_ARRAY_FOREACH(rj, records) {
1673 _cleanup_(event_log_record_freep) EventLogRecord *record = NULL;
1674
1675 if (!GREEDY_REALLOC(variant->records, variant->n_records+1))
1676 return log_oom();
1677
1678 record = event_log_record_new(el);
1679 if (!record)
1680 return log_oom();
1681
1682 r = event_log_record_parse_json(record, rj);
1683 if (r < 0)
1684 return r;
1685
1686 record->owning_component_variant = variant;
1687 variant->records[variant->n_records++] = TAKE_PTR(record);
1688 }
1689 }
1690
1691 component->variants[component->n_variants++] = TAKE_PTR(variant);
1692 return 1;
1693 }
1694
1695 static int event_log_add_component_dir(EventLog *el, const char *path, char **base_search) {
1696 _cleanup_free_ char *fname = NULL, *id = NULL;
1697 _cleanup_strv_free_ char **files = NULL;
1698 EventLogComponent *component;
1699 const char *e;
1700 int r;
1701
1702 assert(el);
1703
1704 r = path_extract_filename(path, &fname);
1705 if (r < 0)
1706 return log_error_errno(r, "Failed to extract basename from path %s: %m", path);
1707
1708 e = endswith(fname, ".pcrlock.d");
1709 if (!e)
1710 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad suffix: %s", fname);
1711
1712 id = strndup(fname, e - fname);
1713 if (!id)
1714 return log_oom();
1715
1716 r = event_log_add_component(el, id, &component);
1717 if (r < 0)
1718 return r;
1719
1720 _cleanup_strv_free_ char **search = NULL;
1721
1722 STRV_FOREACH(b, base_search) {
1723 _cleanup_free_ char *q = NULL;
1724
1725 q = path_join(*b, fname);
1726 if (!q)
1727 return log_oom();
1728
1729 r = strv_consume(&search, TAKE_PTR(q));
1730 if (r < 0)
1731 return log_oom();
1732 }
1733
1734 r = conf_files_list_strv(&files, ".pcrlock", /* root= */ NULL, CONF_FILES_REGULAR, (const char*const*) search);
1735 if (r < 0)
1736 return log_error_errno(r, "Failed to enumerate .pcrlock files for component '%s': %m", id);
1737
1738 STRV_FOREACH(f, files) {
1739 r = event_log_add_component_file(el, component, *f);
1740 if (r < 0)
1741 return r;
1742 }
1743
1744 return 0;
1745 }
1746
1747 static int event_log_load_components(EventLog *el) {
1748 _cleanup_strv_free_ char **files = NULL;
1749 char **dirs;
1750 int r;
1751
1752 assert(el);
1753
1754 dirs = arg_components ?:
1755 STRV_MAKE("/etc/pcrlock.d",
1756 "/run/pcrlock.d",
1757 "/var/lib/pcrlock.d",
1758 "/usr/local/lib/pcrlock.d",
1759 "/usr/lib/pcrlock.d");
1760
1761 r = conf_files_list_strv(&files, NULL, NULL, CONF_FILES_REGULAR|CONF_FILES_DIRECTORY|CONF_FILES_FILTER_MASKED, (const char*const*) dirs);
1762 if (r < 0)
1763 return log_error_errno(r, "Failed to enumerate .pcrlock files: %m");
1764
1765 STRV_FOREACH(f, files) {
1766 if (endswith(*f, ".pcrlock.d"))
1767 r = event_log_add_component_dir(el, *f, dirs);
1768 else if (endswith(*f, ".pcrlock"))
1769 r = event_log_add_component_file(el, NULL, *f);
1770 else
1771 continue;
1772 if (r < 0)
1773 return r;
1774 }
1775
1776 return 0;
1777 }
1778
1779 static int event_log_validate_fully_recognized(EventLog *el) {
1780
1781 for (uint32_t pcr = 0; pcr < ELEMENTSOF(el->registers); pcr++) {
1782 bool fully_recognized = true;
1783
1784 FOREACH_ARRAY(rr, el->records, el->n_records) {
1785 EventLogRecord *rec = *rr;
1786
1787 if (rec->pcr != pcr)
1788 continue;
1789
1790 if (rec->n_mapped == 0) {
1791 log_notice("Event log record %zu (PCR %" PRIu32 ", \"%s\") not matching any component.",
1792 (size_t) (rr - el->records), rec->pcr, strna(rec->description));
1793 fully_recognized = false;
1794 break;
1795 }
1796 }
1797
1798 el->registers[pcr].fully_recognized = fully_recognized;
1799 }
1800
1801 return 0;
1802 }
1803
1804 static int event_log_match_component_variant(
1805 EventLog *el,
1806 size_t i,
1807 EventLogComponentVariant *variant,
1808 size_t j,
1809 bool assign) {
1810
1811 int r;
1812
1813 assert(el);
1814 assert(variant);
1815
1816 /* It's OK to point immediately after the last record, but not further */
1817 assert(i <= el->n_records);
1818 assert(j <= variant->n_records);
1819
1820 /* All entries in the variant checked out? Yippieh! */
1821 if (j == variant->n_records)
1822 return true;
1823
1824 /* If the remainder of the variant is longer than the remainder of the event log, it cannot possibly fit. */
1825 if (el->n_records - i < variant->n_records - j)
1826 return false;
1827
1828 /* Does this record match? If not, let's try at the next place in the logs. */
1829 if (!event_log_record_equal(el->records[i], variant->records[j]))
1830 return event_log_match_component_variant(el, i + 1, variant, j, assign); /* Recursion! */
1831
1832 /* This one matches. Good. Let's see if the rest also matches. (Recursion!) */
1833 r = event_log_match_component_variant(el, i + 1, variant, j + 1, assign);
1834 if (r <= 0)
1835 return r;
1836
1837 if (assign) {
1838 /* Take ownership (Note we allow multiple components and variants to take owneship of the same record!) */
1839 if (!GREEDY_REALLOC(el->records[i]->mapped, el->records[i]->n_mapped+1))
1840 return log_oom();
1841
1842 el->records[i]->mapped[el->records[i]->n_mapped++] = variant;
1843 }
1844
1845 return true;
1846 }
1847
1848 static uint32_t event_log_component_variant_pcrs(EventLogComponentVariant *i) {
1849 uint32_t mask = 0;
1850
1851 assert(i);
1852
1853 /* returns mask of PCRs touched by this variant */
1854
1855 FOREACH_ARRAY(rr, i->records, i->n_records)
1856 mask |= UINT32_C(1) << (*rr)->pcr;
1857
1858 return mask;
1859 }
1860
1861 static uint32_t event_log_component_pcrs(EventLogComponent *c) {
1862 uint32_t mask = 0;
1863
1864 assert(c);
1865
1866 /* Returns mask of PCRs touched by this component */
1867
1868 FOREACH_ARRAY(ii, c->variants, c->n_variants)
1869 mask |= event_log_component_variant_pcrs(*ii);
1870
1871 return mask;
1872 }
1873
1874 static int event_log_map_components(EventLog *el) {
1875 _cleanup_free_ char *skipped_ids = NULL;
1876 unsigned n_skipped = 0;
1877 int r;
1878
1879 assert(el);
1880
1881 FOREACH_ARRAY(cc, el->components, el->n_components) {
1882 _cleanup_free_ char *matching_ids = NULL;
1883 unsigned n_matching = 0, n_empty = 0;
1884 EventLogComponent *c = *cc;
1885
1886 if (arg_location_end && strcmp(c->id, arg_location_end) > 0) {
1887 n_skipped++;
1888
1889 if (!strextend_with_separator(&skipped_ids, ", ", c->id))
1890 return log_oom();
1891
1892 continue;
1893 }
1894
1895 FOREACH_ARRAY(ii, c->variants, c->n_variants) {
1896 EventLogComponentVariant *i = *ii;
1897
1898 if (i->n_records == 0) {
1899 /* The empty variant always matches */
1900 n_empty++;
1901 continue;
1902 }
1903
1904 r = event_log_match_component_variant(el, 0, i, 0, n_matching + n_empty == 0);
1905 if (r < 0)
1906 return r;
1907 if (r > 0) {
1908 n_matching++;
1909
1910 if (!strextend_with_separator(&matching_ids, ", ", i->id))
1911 return log_oom();
1912 }
1913 }
1914
1915 if (n_matching + n_empty == 0) {
1916
1917 if (arg_location_start && strcmp(c->id, arg_location_start) >= 0)
1918 log_info("Didn't find component '%s' in event log, assuming system hasn't reached it yet.", c->id);
1919 else {
1920 log_notice("Couldn't find component '%s' in event log.", c->id);
1921 el->n_missing_components++;
1922 el->missing_component_pcrs |= event_log_component_pcrs(c);
1923 }
1924 } else if (n_matching > 1)
1925 log_debug("Found %u possible variants of component '%s' in event log (%s). Proceeding.", n_matching, c->id, matching_ids);
1926 }
1927
1928 if (n_skipped > 0)
1929 log_notice("Skipped %u components after location '%s' (%s).", n_skipped, arg_location_end, skipped_ids);
1930 if (el->n_missing_components > 0)
1931 log_notice("Unable to recognize %zu components in event log.", el->n_missing_components);
1932
1933 return event_log_validate_fully_recognized(el);
1934 }
1935
1936 #define ANSI_TRUE_COLOR_MAX (7U + 3U + 1U + 3U + 1U + 3U + 2U)
1937
1938 static const char *ansi_true_color(uint8_t r, uint8_t g, uint8_t b, char ret[static ANSI_TRUE_COLOR_MAX]) {
1939 snprintf(ret, ANSI_TRUE_COLOR_MAX, "\x1B[38;2;%u;%u;%um", r, g, b);
1940 return ret;
1941 }
1942
1943 static char *color_for_pcr(EventLog *el, uint32_t pcr) {
1944 char color[ANSI_TRUE_COLOR_MAX];
1945 uint8_t r, g, b;
1946
1947 assert(el);
1948 assert(pcr < TPM2_PCRS_MAX);
1949
1950 if (el->registers[pcr].color)
1951 return el->registers[pcr].color;
1952
1953 hsv_to_rgb(360.0 / (TPM2_PCRS_MAX - 1) * pcr, 100, 90, &r, &g, &b);
1954 ansi_true_color(r, g, b, color);
1955
1956 el->registers[pcr].color = strdup(color);
1957 return el->registers[pcr].color;
1958 }
1959
1960 static int add_algorithm_columns(
1961 EventLog *el,
1962 Table *table,
1963 const char *prefix,
1964 const char *json_field_prefix) {
1965
1966 int r;
1967
1968 assert(el);
1969 assert(table);
1970
1971 FOREACH_ARRAY(alg, el->algorithms, el->n_algorithms) {
1972 const char *n = tpm2_hash_alg_to_string(*alg);
1973 _cleanup_free_ char *v = NULL;
1974
1975 if (prefix) {
1976 v = strjoin(prefix, " ", n);
1977 if (!v)
1978 return log_oom();
1979 }
1980
1981 size_t c = table_get_current_column(table);
1982
1983 r = table_add_cell(table, NULL, TABLE_HEADER, v ?: n);
1984 if (r < 0)
1985 return table_log_add_error(r);
1986
1987 if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF) &&
1988 el->primary_algorithm != UINT16_MAX &&
1989 *alg != el->primary_algorithm)
1990 (void) table_hide_column_from_display(table, c);
1991
1992 _cleanup_free_ char *j = NULL;
1993 if (json_field_prefix) {
1994 _cleanup_free_ char *m = strdup(n);
1995 if (!m)
1996 return log_oom();
1997
1998 j = strjoin(json_field_prefix, ascii_strupper(m));
1999 if (!j)
2000 return log_oom();
2001 }
2002
2003 (void) table_set_json_field_name(table, c, j ?: n);
2004 }
2005
2006 return 0;
2007 }
2008
2009 static int show_log_table(EventLog *el, JsonVariant **ret_variant) {
2010 _cleanup_(table_unrefp) Table *table = NULL;
2011 int r;
2012
2013 assert(el);
2014
2015 table = table_new_raw(5 + el->n_algorithms + 4);
2016 if (!table)
2017 return log_oom();
2018
2019 (void) table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
2020
2021 r = table_add_many(table,
2022 TABLE_HEADER, "pcr",
2023 TABLE_SET_ALIGN_PERCENT, 100,
2024 TABLE_HEADER, "",
2025 TABLE_HEADER, "pcrname",
2026 TABLE_HEADER, "event",
2027 TABLE_HEADER, "match",
2028 TABLE_SET_ALIGN_PERCENT, 100);
2029 if (r < 0)
2030 return table_log_add_error(r);
2031
2032 r = add_algorithm_columns(el, table, NULL, NULL);
2033 if (r < 0)
2034 return r;
2035
2036 size_t phase_column = table_get_current_column(table);
2037
2038 r = table_add_many(table,
2039 TABLE_HEADER, "F/U",
2040 TABLE_HEADER, "source",
2041 TABLE_HEADER, "component",
2042 TABLE_HEADER, "description");
2043 if (r < 0)
2044 return table_log_add_error(r);
2045
2046 (void) table_hide_column_from_display(table, table_get_columns(table) - 3); /* hide source */
2047
2048 if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
2049 (void) table_hide_column_from_display(table, (size_t) 1); /* hide color block column */
2050
2051 (void) table_set_json_field_name(table, phase_column, "phase");
2052
2053 FOREACH_ARRAY(rr, el->records, el->n_records) {
2054 EventLogRecord *record = *rr;
2055
2056 r = table_add_many(table,
2057 TABLE_UINT32, record->pcr,
2058 TABLE_STRING, special_glyph(SPECIAL_GLYPH_FULL_BLOCK),
2059 TABLE_SET_COLOR, color_for_pcr(el, record->pcr),
2060 TABLE_STRING, tpm2_pcr_index_to_string(record->pcr));
2061 if (r < 0)
2062 return table_log_add_error(r);
2063
2064 if (EVENT_LOG_RECORD_IS_FIRMWARE(record)) {
2065 const char *et;
2066
2067 et = tpm2_log_event_type_to_string(record->firmware_event_type);
2068 if (et)
2069 r = table_add_cell(table, NULL, TABLE_STRING, et);
2070 else
2071 r = table_add_cell(table, NULL, TABLE_UINT32_HEX, &record->firmware_event_type);
2072 } else if (EVENT_LOG_RECORD_IS_USERSPACE(record))
2073 r = table_add_cell(table, NULL, TABLE_STRING, tpm2_userspace_event_type_to_string(record->userspace_event_type));
2074 else
2075 r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
2076 if (r < 0)
2077 return table_log_add_error(r);
2078
2079 if (record->event_payload_valid < 0 || record->event_payload_valid == EVENT_PAYLOAD_VALID_DONT_KNOW)
2080 r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
2081 else
2082 r = table_add_many(table,
2083 TABLE_BOOLEAN_CHECKMARK, record->event_payload_valid == EVENT_PAYLOAD_VALID_YES,
2084 TABLE_SET_COLOR, ansi_highlight_green_red(record->event_payload_valid == EVENT_PAYLOAD_VALID_YES));
2085 if (r < 0)
2086 return table_log_add_error(r);
2087
2088 FOREACH_ARRAY(alg, el->algorithms, el->n_algorithms) {
2089 EventLogRecordBank *bank;
2090
2091 bank = event_log_record_find_bank(record, *alg);
2092 if (bank) {
2093 _cleanup_free_ char *hex = NULL;
2094
2095 hex = hexmem(bank->hash.buffer, bank->hash.size);
2096 if (!hex)
2097 return log_oom();
2098
2099 r = table_add_cell(table, NULL, TABLE_STRING, hex);
2100 } else
2101 r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
2102 if (r < 0)
2103 return table_log_add_error(r);
2104 }
2105
2106 r = table_add_many(table,
2107 TABLE_STRING, EVENT_LOG_RECORD_IS_FIRMWARE(record) ? "F" :
2108 EVENT_LOG_RECORD_IS_USERSPACE(record) ? "U" : NULL,
2109 TABLE_PATH_BASENAME, record->source,
2110 TABLE_PATH_BASENAME, record->n_mapped > 0 ? record->mapped[0]->component->id : NULL,
2111 TABLE_STRING, record->description);
2112 if (r < 0)
2113 return table_log_add_error(r);
2114 }
2115
2116 if (ret_variant) {
2117 r = table_to_json(table, ret_variant);
2118 if (r < 0)
2119 return log_error_errno(r, "Failed to format table to JSON: %m");
2120
2121 return 0;
2122 }
2123
2124 r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */true);
2125 if (r < 0)
2126 return log_error_errno(r, "Failed to output table: %m");
2127
2128 return 0;
2129 }
2130
2131 static bool is_unset_pcr(const void *value, size_t size) {
2132 return memeqzero(value, size) || memeqbyte(0xffu, value, size);
2133 }
2134
2135 static bool event_log_pcr_checks_out(const EventLog *el, const EventLogRegister *reg) {
2136 assert(el);
2137 assert(reg);
2138
2139 for (size_t i = 0; i < el->n_algorithms; i++)
2140 if (memcmp_nn(reg->banks[i].calculated.buffer, reg->banks[i].calculated.size,
2141 reg->banks[i].observed.buffer, reg->banks[i].observed.size) != 0)
2142 return false;
2143
2144 return true;
2145 }
2146
2147 static int show_pcr_table(EventLog *el, JsonVariant **ret_variant) {
2148 _cleanup_(table_unrefp) Table *table = NULL;
2149 int r;
2150
2151 assert(el);
2152
2153 table = table_new_raw(8 + el->n_algorithms*2);
2154 if (!table)
2155 return log_oom();
2156
2157 (void) table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
2158
2159 r = table_add_many(table,
2160 TABLE_HEADER, "pcr",
2161 TABLE_SET_ALIGN_PERCENT, 100,
2162 TABLE_HEADER, "", /* color block column */
2163 TABLE_HEADER, "", /* emoji column */
2164 TABLE_HEADER, "pcrname",
2165 TABLE_HEADER, "count",
2166 TABLE_SET_ALIGN_PERCENT, 100,
2167 TABLE_HEADER, "h",
2168 TABLE_SET_ALIGN_PERCENT, 100,
2169 TABLE_HEADER, "r",
2170 TABLE_SET_ALIGN_PERCENT, 100,
2171 TABLE_HEADER, "c",
2172 TABLE_SET_ALIGN_PERCENT, 100);
2173 if (r < 0)
2174 return table_log_add_error(r);
2175
2176 r = add_algorithm_columns(el, table, "Calculated", "calculated");
2177 if (r < 0)
2178 return r;
2179
2180 r = add_algorithm_columns(el, table, "Observed", "observed");
2181 if (r < 0)
2182 return r;
2183
2184 if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
2185 (void) table_hide_column_from_display(table, (size_t) 1, (size_t) 2); /* hide color block and emoji column */
2186 else if (!emoji_enabled())
2187 (void) table_hide_column_from_display(table, (size_t) 2);
2188
2189 (void) table_set_json_field_name(table, 5, "hashMatchesEventLog");
2190 (void) table_set_json_field_name(table, 6, "allEventsMatched");
2191 (void) table_set_json_field_name(table, 7, "noMissingComponents");
2192
2193 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
2194 /* Check if the PCR hash value matches the event log data */
2195 bool hash_match = event_log_pcr_checks_out(el, el->registers + pcr);
2196
2197 /* Whether all records in this PCR have a matching component */
2198 bool fully_recognized = el->registers[pcr].fully_recognized;
2199
2200 /* Whether any unmatched components touch this PCR */
2201 bool missing_components = FLAGS_SET(el->missing_component_pcrs, UINT32_C(1) << pcr);
2202
2203 const char *emoji = special_glyph(
2204 !hash_match ? SPECIAL_GLYPH_DEPRESSED_SMILEY :
2205 !fully_recognized ? SPECIAL_GLYPH_UNHAPPY_SMILEY :
2206 missing_components ? SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY :
2207 SPECIAL_GLYPH_HAPPY_SMILEY);
2208
2209 r = table_add_many(table,
2210 TABLE_UINT32, pcr,
2211 TABLE_STRING, special_glyph(SPECIAL_GLYPH_FULL_BLOCK),
2212 TABLE_SET_COLOR, color_for_pcr(el, pcr),
2213 TABLE_STRING, emoji,
2214 TABLE_STRING, tpm2_pcr_index_to_string(pcr));
2215 if (r < 0)
2216 return table_log_add_error(r);
2217
2218 if (el->registers[pcr].n_measurements > 0)
2219 r = table_add_cell(table, NULL, TABLE_UINT, &el->registers[pcr].n_measurements);
2220 else
2221 r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
2222 if (r < 0)
2223 return table_log_add_error(r);
2224
2225 r = table_add_many(table,
2226 TABLE_BOOLEAN_CHECKMARK, hash_match,
2227 TABLE_SET_COLOR, ansi_highlight_green_red(hash_match),
2228 TABLE_BOOLEAN_CHECKMARK, fully_recognized,
2229 TABLE_SET_COLOR, ansi_highlight_green_red(fully_recognized),
2230 TABLE_BOOLEAN_CHECKMARK, !missing_components,
2231 TABLE_SET_COLOR, ansi_highlight_green_red(!missing_components));
2232 if (r < 0)
2233 return table_log_add_error(r);
2234
2235 for (size_t i = 0; i < el->n_algorithms; i++) {
2236 const char *color;
2237
2238 color = is_unset_pcr(el->registers[pcr].banks[i].calculated.buffer, el->registers[pcr].banks[i].calculated.size) ? ANSI_GREY : NULL;
2239
2240 if (el->registers[pcr].banks[i].calculated.size > 0) {
2241 _cleanup_free_ char *hex = NULL;
2242
2243 hex = hexmem(el->registers[pcr].banks[i].calculated.buffer, el->registers[pcr].banks[i].calculated.size);
2244 if (!hex)
2245 return log_oom();
2246
2247 r = table_add_many(table,
2248 TABLE_STRING, hex,
2249 TABLE_SET_COLOR, color);
2250 } else
2251 r = table_add_many(table,
2252 TABLE_EMPTY,
2253 TABLE_SET_COLOR, color);
2254 if (r < 0)
2255 return table_log_add_error(r);
2256 }
2257
2258 for (size_t i = 0; i < el->n_algorithms; i++) {
2259 _cleanup_free_ char *hex = NULL;
2260 const char *color;
2261
2262 hex = hexmem(el->registers[pcr].banks[i].observed.buffer, el->registers[pcr].banks[i].observed.size);
2263 if (!hex)
2264 return log_oom();
2265
2266 color = !hash_match ? ANSI_HIGHLIGHT_RED :
2267 is_unset_pcr(el->registers[pcr].banks[i].observed.buffer, el->registers[pcr].banks[i].observed.size) ? ANSI_GREY : NULL;
2268
2269 r = table_add_many(table,
2270 TABLE_STRING, hex,
2271 TABLE_SET_COLOR, color);
2272 if (r < 0)
2273 return table_log_add_error(r);
2274 }
2275 }
2276
2277 if (ret_variant) {
2278 r = table_to_json(table, ret_variant);
2279 if (r < 0)
2280 return log_error_errno(r, "Failed to format table to JSON: %m");
2281
2282 return 0;
2283 }
2284
2285 r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */ true);
2286 if (r < 0)
2287 return log_error_errno(r, "Failed to output table: %m");
2288
2289 if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF))
2290 printf("\n"
2291 "%sLegend: H → PCR hash value matches event log%s\n"
2292 "%s R → All event log records for this PCR have a matching component%s\n"
2293 "%s C → No components that couldn't be matched with log records affect this PCR%s\n",
2294 ansi_grey(), ansi_normal(), /* less on small screens automatically resets the color after long lines, hence we set it anew for each line */
2295 ansi_grey(), ansi_normal(),
2296 ansi_grey(), ansi_normal());
2297
2298 return 0;
2299 }
2300
2301 static int event_determine_primary_algorithm(EventLog *el) {
2302 assert(el);
2303
2304 if (el->n_algorithms == 0) {
2305 /* Nothing loaded to make the decision on? Then pick SHA256 */
2306 el->primary_algorithm = TPM2_ALG_SHA256;
2307 return 0;
2308 }
2309
2310 FOREACH_ARRAY(alg, el->algorithms, el->n_algorithms) {
2311 /* If we have SHA256, focus on that that */
2312
2313 if (*alg == TPM2_ALG_SHA256) {
2314 el->primary_algorithm = *alg;
2315 return 0;
2316 }
2317 }
2318
2319 /* Otherwise show the "best" (i.e. the one with the highest id value) */
2320 el->primary_algorithm = el->algorithms[el->n_algorithms-1];
2321 return 0;
2322 }
2323
2324 static int event_log_load_and_process(EventLog **ret) {
2325 _cleanup_(event_log_freep) EventLog *el = NULL;
2326 int r;
2327
2328 el = event_log_new();
2329 if (!el)
2330 return log_oom();
2331
2332 r = event_log_add_algorithms_from_environment(el);
2333 if (r < 0)
2334 return r;
2335
2336 r = event_log_load(el);
2337 if (r < 0)
2338 return r;
2339
2340 r = event_log_read_pcrs(el);
2341 if (r < 0)
2342 return r;
2343
2344 r = event_log_calculate_pcrs(el);
2345 if (r < 0)
2346 return r;
2347
2348 r = event_log_validate_record_hashes(el);
2349 if (r < 0)
2350 return r;
2351
2352 r = event_determine_primary_algorithm(el);
2353 if (r < 0)
2354 return r;
2355
2356 r = event_log_load_components(el);
2357 if (r < 0)
2358 return r;
2359
2360 r = event_log_map_components(el);
2361 if (r < 0)
2362 return r;
2363
2364 *ret = TAKE_PTR(el);
2365 return 0;
2366 }
2367
2368 static int verb_show_log(int argc, char *argv[], void *userdata) {
2369 _cleanup_(json_variant_unrefp) JsonVariant *log_table = NULL, *pcr_table = NULL;
2370 _cleanup_(event_log_freep) EventLog *el = NULL;
2371 bool want_json = !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF);
2372 int r;
2373
2374 r = event_log_load_and_process(&el);
2375 if (r < 0)
2376 return r;
2377
2378 if (!want_json)
2379 putchar('\n');
2380
2381 r = show_log_table(el, want_json ? &log_table : NULL);
2382 if (r < 0)
2383 return r;
2384
2385 if (!want_json)
2386 putchar('\n');
2387
2388 r = show_pcr_table(el, want_json ? &pcr_table : NULL);
2389 if (r < 0)
2390 return r;
2391
2392 if (want_json) {
2393 _cleanup_(json_variant_unrefp) JsonVariant *object = NULL;
2394
2395 r = json_build(&object, JSON_BUILD_OBJECT(
2396 JSON_BUILD_PAIR_VARIANT("log", log_table),
2397 JSON_BUILD_PAIR_VARIANT("pcrs", pcr_table)));
2398 if (r < 0)
2399 return log_error_errno(r, "Failed to generate combined object: %m");
2400
2401 r = json_variant_dump(object, arg_json_format_flags, stdout, /* prefix= */ NULL);
2402 if (r < 0)
2403 return log_error_errno(r, "Failed to dump JSON object: %m");
2404 }
2405
2406 return 0;
2407 }
2408
2409 static int verb_show_cel(int argc, char *argv[], void *userdata) {
2410 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
2411 _cleanup_(event_log_freep) EventLog *el = NULL;
2412 uint64_t recnum = 0;
2413 int r;
2414
2415 el = event_log_new();
2416 if (!el)
2417 return log_oom();
2418
2419 r = event_log_load(el);
2420 if (r < 0)
2421 return r;
2422
2423 /* Output the event log in TCG CEL-JSON. */
2424
2425 FOREACH_ARRAY(rr, el->records, el->n_records) {
2426 _cleanup_(json_variant_unrefp) JsonVariant *ja = NULL, *fj = NULL;
2427 EventLogRecord *record = *rr;
2428 JsonVariant *cd = NULL;
2429 const char *ct = NULL;
2430
2431 LIST_FOREACH(banks, bank, record->banks) {
2432 r = json_variant_append_arrayb(
2433 &ja, JSON_BUILD_OBJECT(
2434 JSON_BUILD_PAIR_STRING("hashAlg", tpm2_hash_alg_to_string(bank->algorithm)),
2435 JSON_BUILD_PAIR_HEX("digest", bank->hash.buffer, bank->hash.size)));
2436 if (r < 0)
2437 return log_error_errno(r, "Failed to append CEL digest entry: %m");
2438 }
2439
2440 if (!ja) {
2441 r = json_variant_new_array(&ja, NULL, 0);
2442 if (r < 0)
2443 return log_error_errno(r, "Failed to allocate JSON array: %m");
2444 }
2445
2446 if (EVENT_LOG_RECORD_IS_FIRMWARE(record)) {
2447 _cleanup_free_ char *et = NULL;
2448 const char *z;
2449
2450 z = tpm2_log_event_type_to_string(record->firmware_event_type);
2451 if (z) {
2452 _cleanup_free_ char *b = NULL;
2453
2454 b = strreplace(z, "-", "_");
2455 if (!b)
2456 return log_oom();
2457
2458 et = strjoin("EV_", ascii_strupper(b));
2459 if (!et)
2460 return log_oom();
2461 } else if (asprintf(&et, "%" PRIu32, record->firmware_event_type) < 0)
2462 return log_oom();
2463
2464 r = json_build(&fj, JSON_BUILD_OBJECT(
2465 JSON_BUILD_PAIR_STRING("event_type", et),
2466 JSON_BUILD_PAIR_HEX("event_data", record->firmware_payload, record->firmware_payload_size)));
2467 if (r < 0)
2468 return log_error_errno(r, "Failed to build firmware event data: %m");
2469
2470 cd = fj;
2471 ct = "pcclient_std";
2472 } else if (EVENT_LOG_RECORD_IS_USERSPACE(record)) {
2473 cd = record->userspace_content;
2474 ct = "systemd";
2475 }
2476
2477 r = json_variant_append_arrayb(&array,
2478 JSON_BUILD_OBJECT(
2479 JSON_BUILD_PAIR_UNSIGNED("pcr", record->pcr),
2480 JSON_BUILD_PAIR_UNSIGNED("recnum", ++recnum),
2481 JSON_BUILD_PAIR_VARIANT("digests", ja),
2482 JSON_BUILD_PAIR_CONDITION(ct, "content_type", JSON_BUILD_STRING(ct)),
2483 JSON_BUILD_PAIR_CONDITION(cd, "content", JSON_BUILD_VARIANT(cd))));
2484 if (r < 0)
2485 return log_error_errno(r, "Failed to append CEL record: %m");
2486 }
2487
2488 if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO))
2489 pager_open(arg_pager_flags);
2490
2491 json_variant_dump(array, arg_json_format_flags|JSON_FORMAT_EMPTY_ARRAY, stdout, NULL);
2492 return 0;
2493 }
2494
2495 static int verb_list_components(int argc, char *argv[], void *userdata) {
2496 _cleanup_(event_log_freep) EventLog *el = NULL;
2497 _cleanup_(table_unrefp) Table *table = NULL;
2498 enum {
2499 BEFORE_LOCATION,
2500 BETWEEN_LOCATION,
2501 AFTER_LOCATION,
2502 } loc = BEFORE_LOCATION;
2503 int r;
2504
2505 el = event_log_new();
2506 if (!el)
2507 return log_oom();
2508
2509 r = event_log_add_algorithms_from_environment(el);
2510 if (r < 0)
2511 return r;
2512
2513 r = event_determine_primary_algorithm(el);
2514 if (r < 0)
2515 return r;
2516
2517 r = event_log_load_components(el);
2518 if (r < 0)
2519 return r;
2520
2521 table = table_new("id", "variants");
2522 if (!table)
2523 return log_oom();
2524
2525 FOREACH_ARRAY(c, el->components, el->n_components) {
2526
2527 if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
2528 _cleanup_free_ char *marker = NULL;
2529
2530 switch (loc) {
2531
2532 case BEFORE_LOCATION:
2533 if (arg_location_end && strcmp((*c)->id, arg_location_end) >= 0) {
2534 loc = AFTER_LOCATION;
2535 marker = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), " location '", arg_location_end, "' ", special_glyph(SPECIAL_GLYPH_ARROW_LEFT));
2536 } else if (arg_location_start && strcmp((*c)->id, arg_location_start) >= 0) {
2537 loc = BETWEEN_LOCATION;
2538 marker = strjoin(special_glyph(SPECIAL_GLYPH_TREE_TOP), " start location '", arg_location_start, "' ", special_glyph(SPECIAL_GLYPH_ARROW_DOWN));
2539 }
2540
2541 break;
2542
2543 case BETWEEN_LOCATION:
2544 if (arg_location_end && strcmp((*c)->id, arg_location_end) >= 0) {
2545 loc = AFTER_LOCATION;
2546 marker = strjoin(special_glyph(SPECIAL_GLYPH_TREE_RIGHT), " end location '", arg_location_end, "' ", special_glyph(SPECIAL_GLYPH_ARROW_UP));
2547 }
2548 break;
2549
2550 case AFTER_LOCATION:
2551 break;
2552 }
2553
2554 if (marker) {
2555 r = table_add_many(table,
2556 TABLE_STRING, marker,
2557 TABLE_SET_COLOR, ANSI_GREY,
2558 TABLE_EMPTY);
2559 if (r < 0)
2560 return table_log_add_error(r);
2561 }
2562 }
2563
2564 FOREACH_ARRAY(variant, (*c)->variants, (*c)->n_variants) {
2565 r = table_add_many(table,
2566 TABLE_STRING, (*c)->id,
2567 TABLE_PATH, (*variant)->path);
2568 if (r < 0)
2569 return table_log_add_error(r);
2570 }
2571 }
2572
2573 if (table_get_rows(table) > 1 || !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
2574 r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */ true);
2575 if (r < 0)
2576 return log_error_errno(r, "Failed to output table: %m");
2577 }
2578
2579 if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
2580 if (table_get_rows(table) > 1)
2581 printf("\n%zu components listed.\n", table_get_rows(table) - 1);
2582 else
2583 printf("No components defined.\n");
2584 }
2585
2586 return 0;
2587 }
2588
2589 static int event_log_pcr_mask_checks_out(EventLog *el, uint32_t mask) {
2590 assert(el);
2591
2592 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
2593
2594 if (!FLAGS_SET(mask, UINT32_C(1) << pcr))
2595 continue;
2596
2597 if (!event_log_pcr_checks_out(el, el->registers + pcr))
2598 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Event log for PCR %" PRIu32 " does not match PCR state, refusing.", pcr);
2599 }
2600
2601 return 0;
2602 }
2603
2604 static int make_pcrlock_record(
2605 uint32_t pcr,
2606 const void *data,
2607 size_t data_size,
2608 JsonVariant **ret_record) {
2609
2610 _cleanup_(json_variant_unrefp) JsonVariant *digests = NULL;
2611 int r;
2612
2613 assert(data || data_size == 0);
2614 assert(ret_record);
2615
2616 if (data_size == SIZE_MAX)
2617 data_size = strlen(data);
2618
2619 /* Generates a .pcrlock record for the given PCR and data/data size. This is a subset of TCG CEL. */
2620
2621 FOREACH_ARRAY(pa, tpm2_hash_algorithms, TPM2_N_HASH_ALGORITHMS) {
2622 _cleanup_free_ unsigned char *hash = NULL;
2623 int hash_ssize;
2624 unsigned hash_usize;
2625 const EVP_MD *md;
2626 const char *a;
2627
2628 assert_se(a = tpm2_hash_alg_to_string(*pa));
2629 assert_se(md = EVP_get_digestbyname(a));
2630 hash_ssize = EVP_MD_size(md);
2631 assert_se(hash_ssize > 0);
2632 hash_usize = hash_ssize;
2633
2634 hash = malloc(hash_usize);
2635 if (!hash)
2636 return log_oom();
2637
2638 if (EVP_Digest(data, data_size, hash, &hash_usize, md, NULL) != 1)
2639 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash data with algorithm '%s'.", a);
2640
2641 r = json_variant_append_arrayb(
2642 &digests,
2643 JSON_BUILD_OBJECT(
2644 JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(a)),
2645 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(hash, hash_usize))));
2646 if (r < 0)
2647 return log_error_errno(r, "Failed to build JSON digest object: %m");
2648 }
2649
2650 r = json_build(ret_record,
2651 JSON_BUILD_OBJECT(
2652 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(pcr)),
2653 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(digests))));
2654 if (r < 0)
2655 return log_error_errno(r, "Failed to build record object: %m");
2656
2657 return 0;
2658 }
2659
2660 static const char *pcrlock_path(const char *default_pcrlock_path) {
2661 return arg_pcrlock_path ?: arg_pcrlock_auto ? default_pcrlock_path : NULL;
2662 }
2663
2664 static int write_pcrlock(JsonVariant *array, const char *default_pcrlock_path) {
2665 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *a = NULL;
2666 _cleanup_fclose_ FILE *f = NULL;
2667 const char *p;
2668 int r;
2669
2670 if (!array) {
2671 r = json_variant_new_array(&a, NULL, 0);
2672 if (r < 0)
2673 return log_error_errno(r, "Failed to allocate empty array: %m");
2674
2675 array = a;
2676 }
2677
2678 r = json_build(&v, JSON_BUILD_OBJECT(
2679 JSON_BUILD_PAIR("records", JSON_BUILD_VARIANT(array))));
2680 if (r < 0)
2681 return log_error_errno(r, "Failed to build JSON object: %m");
2682
2683 p = pcrlock_path(default_pcrlock_path);
2684 if (p) {
2685 (void) mkdir_parents_label(p, 0755);
2686
2687 f = fopen(p, "we");
2688 if (!f)
2689 return log_error_errno(errno, "Failed to open %s for writing: %m", p);
2690 }
2691
2692 r = json_variant_dump(v, arg_json_format_flags, f ?: stdout, /* prefix= */ NULL);
2693 if (r < 0)
2694 return log_error_errno(r, "Failed to output JSON object: %m");
2695
2696 if (p)
2697 log_info("%s written.", p);
2698
2699 return 0;
2700 }
2701
2702 static int unlink_pcrlock(const char *default_pcrlock_path) {
2703 const char *p;
2704
2705 p = pcrlock_path(default_pcrlock_path);
2706 if (!p)
2707 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No .pcrlock path specified, refusing.");
2708
2709 if (unlink(p) < 0) {
2710 if (errno != ENOENT)
2711 return log_error_errno(errno, "Failed to delete %s: %m", p);
2712
2713 log_info("%s already deleted.", p);
2714 } else
2715 log_info("%s deleted.", p);
2716
2717 (void) rmdir_parents(p, "/var/lib");
2718
2719 return 0;
2720 }
2721
2722 static int verb_lock_raw(int argc, char *argv[], void *userdata) {
2723 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
2724 _cleanup_free_ char *data = NULL;
2725 _cleanup_fclose_ FILE *f = NULL;
2726 size_t size;
2727 int r;
2728
2729 if (arg_pcr_mask == 0)
2730 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No PCR specified, refusing.");
2731
2732 if (argc >= 2) {
2733 f = fopen(argv[1], "re");
2734 if (!f)
2735 return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
2736 }
2737
2738 r = read_full_stream(f ?: stdin, &data, &size);
2739 if (r < 0)
2740 return log_error_errno(r, "Failed to read data from stdin: %m");
2741
2742 for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) {
2743 _cleanup_(json_variant_unrefp) JsonVariant *record = NULL;
2744
2745 if (!FLAGS_SET(arg_pcr_mask, UINT32_C(1) << i))
2746 continue;
2747
2748 r = make_pcrlock_record(i, data, size, &record);
2749 if (r < 0)
2750 return r;
2751
2752 r = json_variant_append_array(&array, record);
2753 if (r < 0)
2754 return log_error_errno(r, "Failed to append to JSON array: %m");
2755 }
2756
2757 return write_pcrlock(array, NULL);
2758 }
2759
2760 static int verb_unlock_simple(int argc, char *argv[], void *userdata) {
2761 return unlink_pcrlock(NULL);
2762 }
2763
2764 static int verb_lock_secureboot_policy(int argc, char *argv[], void *userdata) {
2765 static const struct {
2766 sd_id128_t id;
2767 const char *name;
2768 int synthesize_empty; /* 0 → fail, > 0 → synthesize empty db, < 0 → skip */
2769 } variables[] = {
2770 { EFI_VENDOR_GLOBAL, "SecureBoot", 0 },
2771 { EFI_VENDOR_GLOBAL, "PK", 0 },
2772 { EFI_VENDOR_GLOBAL, "KEK", 0 },
2773 { EFI_VENDOR_DATABASE, "db", 1 },
2774 { EFI_VENDOR_DATABASE, "dbx", 1 },
2775 { EFI_VENDOR_DATABASE, "dbt", -1 },
2776 { EFI_VENDOR_DATABASE, "dbr", -1 },
2777 };
2778
2779 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
2780 int r;
2781
2782 /* Generates expected records from the current SecureBoot state, as readable in the EFI variables
2783 * right now. */
2784
2785 FOREACH_ARRAY(vv, variables, ELEMENTSOF(variables)) {
2786 _cleanup_(json_variant_unrefp) JsonVariant *record = NULL;
2787
2788 _cleanup_free_ char *name = NULL;
2789 if (asprintf(&name, "%s-" SD_ID128_UUID_FORMAT_STR, vv->name, SD_ID128_FORMAT_VAL(vv->id)) < 0)
2790 return log_oom();
2791
2792 _cleanup_free_ void *data = NULL;
2793 size_t data_size;
2794 r = efi_get_variable(name, NULL, &data, &data_size);
2795 if (r < 0) {
2796 if (r != -ENOENT || vv->synthesize_empty == 0)
2797 return log_error_errno(r, "Failed to read EFI variable '%s': %m", name);
2798 if (vv->synthesize_empty < 0)
2799 continue;
2800
2801 /* If the main database variables are not set we don't consider this an error, but
2802 * measure an empty database instead. */
2803 log_debug("EFI variable %s is not set, synthesizing empty variable for measurement.", name);
2804 data_size = 0;
2805 }
2806
2807 _cleanup_free_ char16_t* name16 = utf8_to_utf16(vv->name, SIZE_MAX);
2808 if (!name16)
2809 return log_oom();
2810 size_t name16_bytes = char16_strlen(name16) * 2;
2811
2812 size_t vdata_size = offsetof(UEFI_VARIABLE_DATA, unicodeName) + name16_bytes + data_size;
2813 _cleanup_free_ UEFI_VARIABLE_DATA *vdata = malloc(vdata_size);
2814 if (!vdata)
2815 return log_oom();
2816
2817 *vdata = (UEFI_VARIABLE_DATA) {
2818 .unicodeNameLength = name16_bytes / 2,
2819 .variableDataLength = data_size,
2820 };
2821
2822 efi_id128_to_guid(vv->id, vdata->variableName);
2823 memcpy(mempcpy(vdata->unicodeName, name16, name16_bytes), data, data_size);
2824
2825 r = make_pcrlock_record(TPM2_PCR_SECURE_BOOT_POLICY /* =7 */, vdata, vdata_size, &record);
2826 if (r < 0)
2827 return r;
2828
2829 r = json_variant_append_array(&array, record);
2830 if (r < 0)
2831 return log_error_errno(r, "Failed to append to JSON array: %m");
2832 }
2833
2834 return write_pcrlock(array, PCRLOCK_SECUREBOOT_POLICY_PATH);
2835 }
2836
2837 static int verb_unlock_secureboot_policy(int argc, char *argv[], void *userdata) {
2838 return unlink_pcrlock(PCRLOCK_SECUREBOOT_POLICY_PATH);
2839 }
2840
2841 static int event_log_record_is_secureboot_variable(EventLogRecord *rec, sd_id128_t uuid, const char *name) {
2842 _cleanup_free_ char *found_name = NULL;
2843 sd_id128_t found_uuid;
2844 int r;
2845
2846 assert(rec);
2847 assert(name);
2848
2849 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
2850 return false;
2851
2852 if (rec->pcr != TPM2_PCR_SECURE_BOOT_POLICY)
2853 return false;
2854
2855 if (rec->event_payload_valid != EVENT_PAYLOAD_VALID_YES)
2856 return false;
2857
2858 if (rec->firmware_event_type != EV_EFI_VARIABLE_DRIVER_CONFIG)
2859 return false;
2860
2861 r = event_log_record_parse_variable_data(rec, &found_uuid, &found_name);
2862 if (r == -EBADMSG)
2863 return false;
2864 if (r < 0)
2865 return r;
2866
2867 if (!sd_id128_equal(found_uuid, uuid))
2868 return false;
2869
2870 return streq(found_name, name);
2871 }
2872
2873 static bool event_log_record_is_secureboot_authority(EventLogRecord *rec) {
2874 assert(rec);
2875
2876 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
2877 return false;
2878
2879 if (rec->pcr != TPM2_PCR_SECURE_BOOT_POLICY)
2880 return false;
2881
2882 if (rec->event_payload_valid != EVENT_PAYLOAD_VALID_YES)
2883 return false;
2884
2885 return rec->firmware_event_type == EV_EFI_VARIABLE_AUTHORITY;
2886 }
2887
2888 static int event_log_ensure_secureboot_consistency(EventLog *el) {
2889 static const struct {
2890 sd_id128_t id;
2891 const char *name;
2892 bool required;
2893 } table[] = {
2894 { EFI_VENDOR_GLOBAL, "SecureBoot", true },
2895 { EFI_VENDOR_GLOBAL, "PK", true },
2896 { EFI_VENDOR_GLOBAL, "KEK", true },
2897 { EFI_VENDOR_DATABASE, "db", true },
2898 { EFI_VENDOR_DATABASE, "dbx", true },
2899 { EFI_VENDOR_DATABASE, "dbt", false },
2900 { EFI_VENDOR_DATABASE, "dbr", false },
2901 // FIXME: ensure we also find the separator here
2902 };
2903
2904 EventLogRecord *records[ELEMENTSOF(table)] = {};
2905 EventLogRecord *first_authority = NULL;
2906
2907 assert(el);
2908
2909 /* Ensures that the PCR 7 records are complete and in order. Before we lock down PCR 7 we want to
2910 * ensure its state is actually consistent. */
2911
2912 FOREACH_ARRAY(rr, el->records, el->n_records) {
2913 EventLogRecord *rec = *rr;
2914 size_t found = SIZE_MAX;
2915
2916 if (event_log_record_is_secureboot_authority(rec)) {
2917 if (first_authority)
2918 continue;
2919
2920 first_authority = rec;
2921 // FIXME: also check that each authority record's data is also listed in 'db'
2922 continue;
2923 }
2924
2925 for (size_t i = 0; i < ELEMENTSOF(table); i++)
2926 if (event_log_record_is_secureboot_variable(rec, table[i].id, table[i].name)) {
2927 found = i;
2928 break;
2929 }
2930 if (found == SIZE_MAX)
2931 continue;
2932
2933 /* Require the authority records always come *after* database measurements */
2934 if (first_authority)
2935 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "SecureBoot authority before variable, refusing.");
2936
2937 /* Check for duplicates */
2938 if (records[found])
2939 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Duplicate '%s' record, refusing.", rec->description);
2940
2941 /* Check for order */
2942 for (size_t j = found + 1; j < ELEMENTSOF(table); j++)
2943 if (records[j])
2944 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "'%s' record before '%s' record, refusing.", records[j]->description, rec->description);
2945
2946 records[found] = rec;
2947 }
2948
2949 /* Check for existence */
2950 for (size_t i = 0; i < ELEMENTSOF(table); i++)
2951 if (table[i].required && !records[i])
2952 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Required record '%s' not found, refusing.", table[i].name);
2953
2954 /* At this point we know that all required variables have been measured, in the right order. */
2955 return 0;
2956 }
2957
2958 static int verb_lock_secureboot_authority(int argc, char *argv[], void *userdata) {
2959 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
2960 _cleanup_(event_log_freep) EventLog *el = NULL;
2961 int r;
2962
2963 /* Lock down the EV_EFI_VARIABLE_AUTHORITY records from the existing log. Note that there's not too
2964 * much value in locking this down too much, since it stores only the result of the primary database
2965 * checks, and that's what we should bind policy to. Moreover it's hard to predict, since extension
2966 * card firmware validation will result in additional records here. */
2967
2968 if (!is_efi_secure_boot()) {
2969 log_info("SecureBoot disabled, not generating authority .pcrlock file.");
2970 return unlink_pcrlock(PCRLOCK_SECUREBOOT_AUTHORITY_PATH);
2971 }
2972
2973 el = event_log_new();
2974 if (!el)
2975 return log_oom();
2976
2977 r = event_log_add_algorithms_from_environment(el);
2978 if (r < 0)
2979 return r;
2980
2981 r = event_log_load(el);
2982 if (r < 0)
2983 return r;
2984
2985 r = event_log_read_pcrs(el);
2986 if (r < 0)
2987 return r;
2988
2989 r = event_log_calculate_pcrs(el);
2990 if (r < 0)
2991 return r;
2992
2993 /* Before we base anything on the event log records, let's check that the event log state checks
2994 * out. */
2995
2996 r = event_log_pcr_mask_checks_out(el, UINT32_C(1) << TPM2_PCR_SECURE_BOOT_POLICY);
2997 if (r < 0)
2998 return r;
2999
3000 r = event_log_validate_record_hashes(el);
3001 if (r < 0)
3002 return r;
3003
3004 r = event_log_ensure_secureboot_consistency(el);
3005 if (r < 0)
3006 return r;
3007
3008 FOREACH_ARRAY(rr, el->records, el->n_records) {
3009 _cleanup_(json_variant_unrefp) JsonVariant *digests = NULL;
3010 EventLogRecord *rec = *rr;
3011
3012 if (!event_log_record_is_secureboot_authority(rec))
3013 continue;
3014
3015 log_debug("Locking down authority '%s'.", strna(rec->description));
3016
3017 LIST_FOREACH(banks, bank, rec->banks) {
3018 r = json_variant_append_arrayb(
3019 &digests,
3020 JSON_BUILD_OBJECT(
3021 JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(tpm2_hash_alg_to_string(bank->algorithm))),
3022 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(bank->hash.buffer, bank->hash.size))));
3023 if (r < 0)
3024 return log_error_errno(r, "Failed to build digests array: %m");
3025 }
3026
3027 r = json_variant_append_arrayb(
3028 &array,
3029 JSON_BUILD_OBJECT(
3030 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(rec->pcr)),
3031 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(digests))));
3032 if (r < 0)
3033 return log_error_errno(r, "Failed to build record array: %m");
3034 }
3035
3036 return write_pcrlock(array, PCRLOCK_SECUREBOOT_AUTHORITY_PATH);
3037 }
3038
3039 static int verb_unlock_secureboot_authority(int argc, char *argv[], void *userdata) {
3040 return unlink_pcrlock(PCRLOCK_SECUREBOOT_AUTHORITY_PATH);
3041 }
3042
3043 static int verb_lock_gpt(int argc, char *argv[], void *userdata) {
3044 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL, *record = NULL;
3045 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
3046 uint8_t h[2 * 4096]; /* space for at least two 4K sectors. GPT header should definitely be in here */
3047 uint64_t start, n_members, member_size;
3048 _cleanup_close_ int fd = -EBADF;
3049 const GptHeader *p;
3050 size_t found = 0;
3051 ssize_t n;
3052 int r;
3053
3054 r = block_device_new_from_path(
3055 argc >= 2 ? argv[1] : "/",
3056 BLOCK_DEVICE_LOOKUP_WHOLE_DISK|BLOCK_DEVICE_LOOKUP_BACKING|BLOCK_DEVICE_LOOKUP_ORIGINATING,
3057 &d);
3058 if (r < 0)
3059 return log_error_errno(r, "Failed to determine root block device: %m");
3060
3061 fd = sd_device_open(d, O_CLOEXEC|O_RDONLY|O_NOCTTY);
3062 if (fd < 0)
3063 return log_error_errno(fd, "Failed to open root block device: %m");
3064
3065 n = pread(fd, &h, sizeof(h), 0);
3066 if (n < 0)
3067 return log_error_errno(errno, "Failed to read GPT header of block device: %m");
3068 if ((size_t) n != sizeof(h))
3069 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read trying to read GPT header: %m");
3070
3071 /* Try a couple of sector sizes */
3072 for (size_t sz = 512; sz <= 4096; sz <<= 1) {
3073 assert(sizeof(h) >= sz * 2);
3074 p = (const GptHeader*) (h + sz); /* 2nd sector */
3075
3076 if (!gpt_header_has_signature(p))
3077 continue;
3078
3079 if (found != 0)
3080 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
3081 "Disk has partition table for multiple sector sizes, refusing.");
3082
3083 found = sz;
3084 }
3085
3086 if (found == 0)
3087 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
3088 "Disk does not have GPT partition table, refusing.");
3089
3090 p = (const GptHeader*) (h + found);
3091
3092 if (le32toh(p->header_size) > found)
3093 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
3094 "GPT header size over long (%" PRIu32 "), refusing.", le32toh(p->header_size));
3095
3096 start = le64toh(p->partition_entry_lba);
3097 if (start > UINT64_MAX / found)
3098 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
3099 "Partition table start offset overflow, refusing.");
3100
3101 member_size = le32toh(p->size_of_partition_entry);
3102 if (member_size < sizeof(GptPartitionEntry))
3103 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
3104 "Partition entry size too short, refusing.");
3105
3106 n_members = le32toh(p->number_of_partition_entries);
3107 uint64_t member_bufsz = n_members * member_size;
3108 if (member_bufsz > 1U*1024U*1024U)
3109 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
3110 "Partition table size too large, refusing.");
3111
3112 member_bufsz = ROUND_UP(member_bufsz, found);
3113
3114 _cleanup_free_ void *members = malloc(member_bufsz);
3115 if (!members)
3116 return log_oom();
3117
3118 n = pread(fd, members, member_bufsz, start * found);
3119 if (n < 0)
3120 return log_error_errno(errno, "Failed to read GPT partition table entries: %m");
3121 if ((size_t) n != member_bufsz)
3122 return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading GPT partition table entries: %m");
3123
3124 size_t vdata_size = le32toh(p->header_size) + sizeof(le64_t) + member_size * n_members;
3125 _cleanup_free_ void *vdata = malloc0(vdata_size);
3126 if (!vdata)
3127 return log_oom();
3128
3129 void *n_measured_entries = mempcpy(vdata, p, sizeof(GptHeader)); /* n_measured_entries is a 64bit value */
3130
3131 void *qq = (uint8_t*) n_measured_entries + sizeof(le64_t);
3132
3133 for (uint64_t i = 0; i < n_members; i++) {
3134 const GptPartitionEntry *entry = (const GptPartitionEntry*) ((const uint8_t*) members + (member_size * i));
3135
3136 if (memeqzero(entry->partition_type_guid, sizeof(entry->partition_type_guid)))
3137 continue;
3138
3139 qq = mempcpy(qq, entry, member_size);
3140 unaligned_write_le64(n_measured_entries, unaligned_read_le64(n_measured_entries) + 1);
3141 }
3142
3143 vdata_size = (uint8_t*) qq - (uint8_t*) vdata;
3144
3145 r = make_pcrlock_record(TPM2_PCR_BOOT_LOADER_CONFIG /* =5 */, vdata, vdata_size, &record);
3146 if (r < 0)
3147 return r;
3148
3149 r = json_variant_new_array(&array, &record, 1);
3150 if (r < 0)
3151 return log_error_errno(r, "Failed to append to JSON array: %m");
3152
3153 return write_pcrlock(array, PCRLOCK_GPT_PATH);
3154 }
3155
3156 static int verb_unlock_gpt(int argc, char *argv[], void *userdata) {
3157 return unlink_pcrlock(PCRLOCK_GPT_PATH);
3158 }
3159
3160 static bool event_log_record_is_separator(const EventLogRecord *rec) {
3161 assert(rec);
3162
3163 /* Recognizes EV_SEPARATOR events */
3164
3165 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
3166 return false;
3167
3168 if (rec->firmware_event_type != EV_SEPARATOR)
3169 return false;
3170
3171 return rec->event_payload_valid == EVENT_PAYLOAD_VALID_YES; /* Insist the record is consistent */
3172 }
3173
3174 static int event_log_record_is_action_calling_efi_app(const EventLogRecord *rec) {
3175 _cleanup_free_ char *d = NULL;
3176 int r;
3177
3178 assert(rec);
3179
3180 /* Recognizes the special EV_EFI_ACTION that is issues when the firmware passes control to the boot loader. */
3181
3182 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
3183 return false;
3184
3185 if (rec->pcr != TPM2_PCR_BOOT_LOADER_CODE)
3186 return false;
3187
3188 if (rec->firmware_event_type != EV_EFI_ACTION)
3189 return false;
3190
3191 if (rec->event_payload_valid != EVENT_PAYLOAD_VALID_YES) /* Insist the record is consistent */
3192 return false;
3193
3194 r = make_cstring(rec->firmware_payload, rec->firmware_payload_size, MAKE_CSTRING_ALLOW_TRAILING_NUL, &d);
3195 if (r < 0)
3196 return r;
3197
3198 return streq(d, "Calling EFI Application from Boot Option");
3199 }
3200
3201 static void enable_json_sse(void) {
3202 /* We shall write this to a single output stream? We have to output two files, hence try to be smart
3203 * and enable JSON SSE */
3204
3205 if (!arg_pcrlock_path && arg_pcrlock_auto)
3206 return;
3207
3208 if (FLAGS_SET(arg_json_format_flags, JSON_FORMAT_SSE))
3209 return;
3210
3211 log_notice("Enabling JSON_SEQ mode, since writing two .pcrlock files to single output.");
3212 arg_json_format_flags |= JSON_FORMAT_SSE;
3213 }
3214
3215 static int verb_lock_firmware(int argc, char *argv[], void *userdata) {
3216 _cleanup_(json_variant_unrefp) JsonVariant *array_early = NULL, *array_late = NULL;
3217 _cleanup_(event_log_freep) EventLog *el = NULL;
3218 uint32_t always_mask, separator_mask, separator_seen_mask = 0, action_seen_mask = 0;
3219 const char *default_pcrlock_early_path, *default_pcrlock_late_path;
3220 int r;
3221
3222 enable_json_sse();
3223
3224 /* The PCRs we intend to cover. Note that we measure firmware, external *and* boot loader code/config
3225 * here – but the latter only until the "separator" events are seen, which tell us where transition
3226 * into OS boot loader happens. This reflects the fact that on some systems the firmware already
3227 * measures some firmware-supplied apps into PCR 4. (e.g. Thinkpad X1 Gen9) */
3228 if (endswith(argv[0], "firmware-code")) {
3229 always_mask = (UINT32_C(1) << TPM2_PCR_PLATFORM_CODE) | /* → 0 */
3230 (UINT32_C(1) << TPM2_PCR_EXTERNAL_CODE); /* → 2 */
3231
3232 separator_mask = UINT32_C(1) << TPM2_PCR_BOOT_LOADER_CODE; /* → 4 */
3233
3234 default_pcrlock_early_path = PCRLOCK_FIRMWARE_CODE_EARLY_PATH;
3235 default_pcrlock_late_path = PCRLOCK_FIRMWARE_CODE_LATE_PATH;
3236 } else {
3237 assert(endswith(argv[0], "firmware-config"));
3238 always_mask = (UINT32_C(1) << TPM2_PCR_PLATFORM_CONFIG) | /* → 1 */
3239 (UINT32_C(1) << TPM2_PCR_EXTERNAL_CONFIG); /* → 3 */
3240
3241 separator_mask = UINT32_C(1) << TPM2_PCR_BOOT_LOADER_CONFIG; /* → 5 */
3242
3243 default_pcrlock_early_path = PCRLOCK_FIRMWARE_CONFIG_EARLY_PATH;
3244 default_pcrlock_late_path = PCRLOCK_FIRMWARE_CONFIG_LATE_PATH;
3245 }
3246
3247 el = event_log_new();
3248 if (!el)
3249 return log_oom();
3250
3251 r = event_log_add_algorithms_from_environment(el);
3252 if (r < 0)
3253 return r;
3254
3255 r = event_log_load(el);
3256 if (r < 0)
3257 return r;
3258
3259 r = event_log_read_pcrs(el);
3260 if (r < 0)
3261 return r;
3262
3263 r = event_log_calculate_pcrs(el);
3264 if (r < 0)
3265 return r;
3266
3267 r = event_log_validate_record_hashes(el);
3268 if (r < 0)
3269 return r;
3270
3271 /* Before we base anything on the event log records for any of the selected PCRs, let's check that
3272 * the event log state checks out for them. */
3273
3274 r = event_log_pcr_mask_checks_out(el, always_mask|separator_mask);
3275 if (r < 0)
3276 return r;
3277
3278 // FIXME: before doing this, validate ahead-of-time that EV_SEPARATOR records exist for all entries,
3279 // and exactly once
3280
3281 FOREACH_ARRAY(rr, el->records, el->n_records) {
3282 _cleanup_(json_variant_unrefp) JsonVariant *digests = NULL;
3283 EventLogRecord *rec = *rr;
3284 uint32_t bit = UINT32_C(1) << rec->pcr;
3285
3286 if (!EVENT_LOG_RECORD_IS_FIRMWARE(rec))
3287 continue;
3288
3289 if (!FLAGS_SET(always_mask, bit) &&
3290 !(FLAGS_SET(separator_mask, bit) && !FLAGS_SET(separator_seen_mask|action_seen_mask, bit)))
3291 continue;
3292
3293 /* If we hit the separator record, we stop processing the PCRs listed in `separator_mask` */
3294 if (event_log_record_is_separator(rec)) {
3295 separator_seen_mask |= bit;
3296 continue;
3297 }
3298
3299 /* If we hit the special "Calling EFI Application from Boot Option" action we treat this the
3300 * same as a separator here, as that's where firmware passes control to boot loader. Note
3301 * that some EFI implementations forget to generate one of them. */
3302 r = event_log_record_is_action_calling_efi_app(rec);
3303 if (r < 0)
3304 return log_error_errno(r, "Failed to check if event is 'Calling EFI Application from Boot Option' action: %m");
3305 if (r > 0) {
3306 action_seen_mask |= bit;
3307 continue;
3308 }
3309
3310 LIST_FOREACH(banks, bank, rec->banks) {
3311 r = json_variant_append_arrayb(
3312 &digests,
3313 JSON_BUILD_OBJECT(
3314 JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(tpm2_hash_alg_to_string(bank->algorithm))),
3315 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(bank->hash.buffer, bank->hash.size))));
3316 if (r < 0)
3317 return log_error_errno(r, "Failed to build digests array: %m");
3318 }
3319
3320 r = json_variant_append_arrayb(
3321 FLAGS_SET(separator_seen_mask, bit) ? &array_late : &array_early,
3322 JSON_BUILD_OBJECT(
3323 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(rec->pcr)),
3324 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(digests))));
3325 if (r < 0)
3326 return log_error_errno(r, "Failed to build record array: %m");
3327 }
3328
3329 r = write_pcrlock(array_early, default_pcrlock_early_path);
3330 if (r < 0)
3331 return r;
3332
3333 return write_pcrlock(array_late, default_pcrlock_late_path);
3334 }
3335
3336 static int verb_unlock_firmware(int argc, char *argv[], void *userdata) {
3337 const char *default_pcrlock_early_path, *default_pcrlock_late_path;
3338 int r;
3339
3340 if (endswith(argv[0], "firmware-code")) {
3341 default_pcrlock_early_path = PCRLOCK_FIRMWARE_CODE_EARLY_PATH;
3342 default_pcrlock_late_path = PCRLOCK_FIRMWARE_CODE_LATE_PATH;
3343 } else {
3344 default_pcrlock_early_path = PCRLOCK_FIRMWARE_CONFIG_EARLY_PATH;
3345 default_pcrlock_late_path = PCRLOCK_FIRMWARE_CONFIG_LATE_PATH;
3346 }
3347
3348 r = unlink_pcrlock(default_pcrlock_early_path);
3349 if (r < 0)
3350 return r;
3351
3352 if (arg_pcrlock_path) /* if the path is specified don't delete the same thing twice */
3353 return 0;
3354
3355 r = unlink_pcrlock(default_pcrlock_late_path);
3356 if (r < 0)
3357 return r;
3358
3359 return 0;
3360 }
3361
3362 static int verb_lock_machine_id(int argc, char *argv[], void *userdata) {
3363 _cleanup_(json_variant_unrefp) JsonVariant *record = NULL, *array = NULL;
3364 _cleanup_free_ char *word = NULL;
3365 int r;
3366
3367 r = pcrextend_machine_id_word(&word);
3368 if (r < 0)
3369 return r;
3370
3371 r = make_pcrlock_record(TPM2_PCR_SYSTEM_IDENTITY /* = 15 */, word, SIZE_MAX, &record);
3372 if (r < 0)
3373 return r;
3374
3375 r = json_variant_new_array(&array, &record, 1);
3376 if (r < 0)
3377 return log_error_errno(r, "Failed to create record array: %m");
3378
3379 return write_pcrlock(array, PCRLOCK_MACHINE_ID_PATH);
3380 }
3381
3382 static int verb_unlock_machine_id(int argc, char *argv[], void *userdata) {
3383 return unlink_pcrlock(PCRLOCK_MACHINE_ID_PATH);
3384 }
3385
3386 static int pcrlock_file_system_path(const char *normalized_path, char **ret) {
3387 _cleanup_free_ char *s = NULL;
3388
3389 assert(normalized_path);
3390
3391 if (path_equal(normalized_path, "/"))
3392 s = strdup(PCRLOCK_ROOT_FILE_SYSTEM_PATH);
3393 else {
3394 /* We reuse the escaping we use for turning paths into unit names */
3395 _cleanup_free_ char *escaped = NULL;
3396
3397 assert(normalized_path[0] == '/');
3398 assert(normalized_path[1] != '/');
3399
3400 escaped = unit_name_escape(normalized_path + 1);
3401 if (!escaped)
3402 return log_oom();
3403
3404 s = strjoin(PCRLOCK_FILE_SYSTEM_PATH_PREFIX, escaped, ".pcrlock");
3405 }
3406 if (!s)
3407 return log_oom();
3408
3409 *ret = TAKE_PTR(s);
3410 return 0;
3411 }
3412
3413 static int verb_lock_file_system(int argc, char *argv[], void *userdata) {
3414 const char* paths[3] = {};
3415 int r;
3416
3417 if (argc > 1)
3418 paths[0] = argv[1];
3419 else {
3420 dev_t a, b;
3421 paths[0] = "/";
3422
3423 r = get_block_device("/", &a);
3424 if (r < 0)
3425 return log_error_errno(r, "Failed to get device of root file system: %m");
3426
3427 r = get_block_device("/var", &b);
3428 if (r < 0)
3429 return log_error_errno(r, "Failed to get device of /var/ file system: %m");
3430
3431 /* if backing device is distinct, then measure /var/ too */
3432 if (a != b)
3433 paths[1] = "/var";
3434
3435 enable_json_sse();
3436 }
3437
3438 STRV_FOREACH(p, paths) {
3439 _cleanup_free_ char *word = NULL, *normalized_path = NULL, *pcrlock_file = NULL;
3440 _cleanup_(json_variant_unrefp) JsonVariant *record = NULL, *array = NULL;
3441
3442 r = pcrextend_file_system_word(*p, &word, &normalized_path);
3443 if (r < 0)
3444 return r;
3445
3446 r = pcrlock_file_system_path(normalized_path, &pcrlock_file);
3447 if (r < 0)
3448 return r;
3449
3450 r = make_pcrlock_record(TPM2_PCR_SYSTEM_IDENTITY /* = 15 */, word, SIZE_MAX, &record);
3451 if (r < 0)
3452 return r;
3453
3454 r = json_variant_new_array(&array, &record, 1);
3455 if (r < 0)
3456 return log_error_errno(r, "Failed to create record array: %m");
3457
3458 r = write_pcrlock(array, pcrlock_file);
3459 if (r < 0)
3460 return r;
3461 }
3462
3463 return 0;
3464 }
3465
3466 static int verb_unlock_file_system(int argc, char *argv[], void *userdata) {
3467 const char* paths[3] = {};
3468 int r;
3469
3470 if (argc > 1)
3471 paths[0] = argv[1];
3472 else {
3473 paths[0] = "/";
3474 paths[1] = "/var";
3475 }
3476
3477 STRV_FOREACH(p, paths) {
3478 _cleanup_free_ char *normalized_path = NULL, *pcrlock_file = NULL;
3479
3480 r = chase(*p, NULL, 0, &normalized_path, NULL);
3481 if (r < 0)
3482 return log_error_errno(r, "Failed to normal path '%s': %m", argv[1]);
3483
3484 r = pcrlock_file_system_path(normalized_path, &pcrlock_file);
3485 if (r < 0)
3486 return r;
3487
3488 r = unlink_pcrlock(pcrlock_file);
3489 if (r < 0)
3490 return r;
3491 }
3492
3493 return 0;
3494 }
3495
3496 static int verb_lock_pe(int argc, char *argv[], void *userdata) {
3497 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
3498 _cleanup_close_ int fd = -EBADF;
3499 int r;
3500
3501 // FIXME: Maybe also generate a matching EV_EFI_VARIABLE_AUTHORITY records here for each signature that
3502 // covers this PE plus its hash, as alternatives under the same component name
3503
3504 if (argc >= 2) {
3505 fd = open(argv[1], O_RDONLY|O_CLOEXEC);
3506 if (fd < 0)
3507 return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
3508 }
3509
3510 if (arg_pcr_mask == 0)
3511 arg_pcr_mask = UINT32_C(1) << TPM2_PCR_BOOT_LOADER_CODE;
3512
3513 for (uint32_t i = 0; i < TPM2_PCRS_MAX; i++) {
3514 _cleanup_(json_variant_unrefp) JsonVariant *digests = NULL;
3515
3516 if (!FLAGS_SET(arg_pcr_mask, UINT32_C(1) << i))
3517 continue;
3518
3519 FOREACH_ARRAY(pa, tpm2_hash_algorithms, TPM2_N_HASH_ALGORITHMS) {
3520 _cleanup_free_ void *hash = NULL;
3521 size_t hash_size;
3522 const EVP_MD *md;
3523 const char *a;
3524
3525 assert_se(a = tpm2_hash_alg_to_string(*pa));
3526 assert_se(md = EVP_get_digestbyname(a));
3527
3528 r = pe_hash(fd < 0 ? STDIN_FILENO : fd, md, &hash, &hash_size);
3529 if (r < 0)
3530 return log_error_errno(r, "Failed to hash PE binary: %m");
3531
3532 r = json_variant_append_arrayb(&digests,
3533 JSON_BUILD_OBJECT(
3534 JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(a)),
3535 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(hash, hash_size))));
3536 if (r < 0)
3537 return log_error_errno(r, "Failed to build JSON digest object: %m");
3538 }
3539
3540 r = json_variant_append_arrayb(
3541 &array,
3542 JSON_BUILD_OBJECT(
3543 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(i)),
3544 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(digests))));
3545 if (r < 0)
3546 return log_error_errno(r, "Failed to append record object: %m");
3547 }
3548
3549 return write_pcrlock(array, NULL);
3550 }
3551
3552 typedef void* SectionHashArray[_UNIFIED_SECTION_MAX * TPM2_N_HASH_ALGORITHMS];
3553
3554 static void section_hashes_array_done(SectionHashArray *array) {
3555 assert(array);
3556
3557 for (size_t i = 0; i < _UNIFIED_SECTION_MAX * TPM2_N_HASH_ALGORITHMS; i++)
3558 free((*array)[i]);
3559 }
3560
3561 static int verb_lock_uki(int argc, char *argv[], void *userdata) {
3562 _cleanup_(json_variant_unrefp) JsonVariant *array = NULL, *pe_digests = NULL;
3563 _cleanup_(section_hashes_array_done) SectionHashArray section_hashes = {};
3564 size_t hash_sizes[TPM2_N_HASH_ALGORITHMS];
3565 _cleanup_close_ int fd = -EBADF;
3566 int r;
3567
3568 if (arg_pcr_mask != 0)
3569 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PCR not configurable for UKI lock down.");
3570
3571 if (argc >= 2) {
3572 fd = open(argv[1], O_RDONLY|O_CLOEXEC);
3573 if (fd < 0)
3574 return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
3575 }
3576
3577 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
3578 _cleanup_free_ void *peh = NULL;
3579 const EVP_MD *md;
3580 const char *a;
3581
3582 assert_se(a = tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]));
3583 assert_se(md = EVP_get_digestbyname(a));
3584
3585 r = pe_hash(fd < 0 ? STDIN_FILENO : fd, md, &peh, hash_sizes + i);
3586 if (r < 0)
3587 return log_error_errno(r, "Failed to hash PE binary: %m");
3588
3589 r = json_variant_append_arrayb(
3590 &pe_digests,
3591 JSON_BUILD_OBJECT(
3592 JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(a)),
3593 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(peh, hash_sizes[i]))));
3594 if (r < 0)
3595 return log_error_errno(r, "Failed to build JSON digest object: %m");
3596
3597 r = uki_hash(fd < 0 ? STDIN_FILENO : fd, md, section_hashes + (i * _UNIFIED_SECTION_MAX), hash_sizes + i);
3598 if (r < 0)
3599 return log_error_errno(r, "Failed to UKI hash PE binary: %m");
3600 }
3601
3602 r = json_variant_append_arrayb(
3603 &array,
3604 JSON_BUILD_OBJECT(
3605 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(TPM2_PCR_BOOT_LOADER_CODE)),
3606 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(pe_digests))));
3607 if (r < 0)
3608 return log_error_errno(r, "Failed to append record object: %m");
3609
3610 for (UnifiedSection section = 0; section < _UNIFIED_SECTION_MAX; section++) {
3611 _cleanup_(json_variant_unrefp) JsonVariant *section_digests = NULL, *record = NULL;
3612
3613 if (!unified_section_measure(section))
3614 continue;
3615
3616 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
3617 const char *a;
3618 void *hash;
3619
3620 hash = section_hashes[i * _UNIFIED_SECTION_MAX + section];
3621 if (!hash)
3622 continue;
3623
3624 assert_se(a = tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]));
3625
3626 r = json_variant_append_arrayb(
3627 &section_digests,
3628 JSON_BUILD_OBJECT(
3629 JSON_BUILD_PAIR("hashAlg", JSON_BUILD_STRING(a)),
3630 JSON_BUILD_PAIR("digest", JSON_BUILD_HEX(hash, hash_sizes[i]))));
3631 if (r < 0)
3632 return log_error_errno(r, "Failed to build JSON digest object: %m");
3633 }
3634
3635 if (!section_digests)
3636 continue;
3637
3638 /* So we have digests for this section, hence generate a record for the section name first. */
3639 r = make_pcrlock_record(TPM2_PCR_KERNEL_BOOT /* =11 */, unified_sections[section], strlen(unified_sections[section]) + 1, &record);
3640 if (r < 0)
3641 return r;
3642
3643 r = json_variant_append_array(&array, record);
3644 if (r < 0)
3645 return log_error_errno(r, "Failed to append JSON record array: %m");
3646
3647 /* And then append a record for the section contents digests as well */
3648 r = json_variant_append_arrayb(
3649 &array,
3650 JSON_BUILD_OBJECT(
3651 JSON_BUILD_PAIR("pcr", JSON_BUILD_UNSIGNED(TPM2_PCR_KERNEL_BOOT /* =11 */)),
3652 JSON_BUILD_PAIR("digests", JSON_BUILD_VARIANT(section_digests))));
3653 if (r < 0)
3654 return log_error_errno(r, "Failed to append record object: %m");
3655 }
3656
3657 return write_pcrlock(array, NULL);
3658 }
3659
3660 static int event_log_reduce_to_safe_pcrs(EventLog *el, uint32_t *pcrs) {
3661 _cleanup_free_ char *dropped = NULL, *kept = NULL;
3662
3663 assert(el);
3664 assert(pcrs);
3665
3666 /* When we compile a new PCR policy we don't want to bind to PCRs which are fishy for one of three
3667 * reasons:
3668 *
3669 * 1. The PCR value doesn't match the event log
3670 * 2. The event log for the PCR contains measurements we don't know responsible components for
3671 * 3. The event log for the PCR does not contain measurements for components we know
3672 *
3673 * This function checks for the three conditions and drops the PCR from the mask.
3674 */
3675
3676 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
3677
3678 if (!FLAGS_SET(*pcrs, UINT32_C(1) << pcr))
3679 continue;
3680
3681 if (!event_log_pcr_checks_out(el, el->registers + pcr)) {
3682 log_notice("PCR %" PRIu32 " (%s) value does not match event log. Removing from set of PCRs.", pcr, strna(tpm2_pcr_index_to_string(pcr)));
3683 goto drop;
3684 }
3685
3686 if (!el->registers[pcr].fully_recognized) {
3687 log_notice("PCR %" PRIu32 " (%s) event log contains unrecognized measurements. Removing from set of PCRs.", pcr, strna(tpm2_pcr_index_to_string(pcr)));
3688 goto drop;
3689 }
3690
3691 if (FLAGS_SET(el->missing_component_pcrs, UINT32_C(1) << pcr)) {
3692 log_notice("PCR %" PRIu32 " (%s) is touched by component we can't find in event log. Removing from set of PCRs.", pcr, strna(tpm2_pcr_index_to_string(pcr)));
3693 goto drop;
3694 }
3695
3696 log_info("PCR %" PRIu32 " (%s) matches event log and fully consists of recognized measurements. Including in set of PCRs.", pcr, strna(tpm2_pcr_index_to_string(pcr)));
3697
3698 if (strextendf_with_separator(&kept, ", ", "%" PRIu32 " (%s)", pcr, tpm2_pcr_index_to_string(pcr)) < 0)
3699 return log_oom();
3700
3701 continue;
3702
3703 drop:
3704 *pcrs &= ~(UINT32_C(1) << pcr);
3705
3706 if (strextendf_with_separator(&dropped, ", ", "%" PRIu32 " (%s)", pcr, tpm2_pcr_index_to_string(pcr)) < 0)
3707 return log_oom();
3708 }
3709
3710 if (dropped)
3711 log_notice("PCRs dropped from protection mask: %s", dropped);
3712 else
3713 log_debug("No PCRs dropped from protection mask.");
3714
3715 if (kept)
3716 log_notice("PCRs in protection mask: %s", kept);
3717 else
3718 log_notice("No PCRs kept in protection mask.");
3719
3720 return 0;
3721 }
3722
3723 static int verb_lock_kernel_cmdline(int argc, char *argv[], void *userdata) {
3724 _cleanup_(json_variant_unrefp) JsonVariant *record = NULL, *array = NULL;
3725 _cleanup_free_ char *cmdline = NULL;
3726 int r;
3727
3728 if (argc > 1) {
3729 if (empty_or_dash(argv[1]))
3730 r = read_full_stream(stdin, &cmdline, NULL);
3731 else
3732 r = read_full_file(argv[1], &cmdline, NULL);
3733 } else
3734 r = proc_cmdline(&cmdline);
3735 if (r < 0)
3736 return log_error_errno(r, "Failed to read cmdline: %m");
3737
3738 delete_trailing_chars(cmdline, "\n");
3739
3740 _cleanup_free_ char16_t *u = NULL;
3741 u = utf8_to_utf16(cmdline, SIZE_MAX);
3742 if (!u)
3743 return log_oom();
3744
3745 r = make_pcrlock_record(TPM2_PCR_KERNEL_INITRD /* = 9 */, u, char16_strlen(u)*2+2, &record);
3746 if (r < 0)
3747 return r;
3748
3749 r = json_variant_new_array(&array, &record, 1);
3750 if (r < 0)
3751 return log_error_errno(r, "Failed to create record array: %m");
3752
3753 r = write_pcrlock(array, PCRLOCK_KERNEL_CMDLINE_PATH);
3754 if (r < 0)
3755 return r;
3756
3757 return 0;
3758 }
3759
3760 static int verb_unlock_kernel_cmdline(int argc, char *argv[], void *userdata) {
3761 return unlink_pcrlock(PCRLOCK_KERNEL_CMDLINE_PATH);
3762 }
3763
3764 static int verb_lock_kernel_initrd(int argc, char *argv[], void *userdata) {
3765 _cleanup_(json_variant_unrefp) JsonVariant *record = NULL, *array = NULL;
3766 _cleanup_free_ void *data = NULL;
3767 _cleanup_fclose_ FILE *f = NULL;
3768 size_t size;
3769 int r;
3770
3771 if (argc >= 2) {
3772 f = fopen(argv[1], "re");
3773 if (!f)
3774 return log_error_errno(errno, "Failed to open '%s': %m", argv[1]);
3775 }
3776
3777 r = read_full_stream(f ?: stdin, (char**) &data, &size);
3778 if (r < 0)
3779 return log_error_errno(r, "Failed to read data from stdin: %m");
3780
3781 r = make_pcrlock_record(TPM2_PCR_KERNEL_INITRD /* = 9 */, data, size, &record);
3782 if (r < 0)
3783 return r;
3784
3785 r = json_variant_new_array(&array, &record, 1);
3786 if (r < 0)
3787 return log_error_errno(r, "Failed to create record array: %m");
3788
3789 r = write_pcrlock(array, PCRLOCK_KERNEL_INITRD_PATH);
3790 if (r < 0)
3791 return r;
3792
3793 return 0;
3794 }
3795
3796 static int verb_unlock_kernel_initrd(int argc, char *argv[], void *userdata) {
3797 return unlink_pcrlock(PCRLOCK_KERNEL_INITRD_PATH);
3798 }
3799
3800 static int pcr_prediction_add_result(
3801 Tpm2PCRPrediction *context,
3802 Tpm2PCRPredictionResult *result,
3803 uint32_t pcr,
3804 const char *path,
3805 size_t offset) {
3806
3807 _cleanup_free_ Tpm2PCRPredictionResult *copy = NULL;
3808 int r;
3809
3810 assert(context);
3811 assert(result);
3812
3813 copy = newdup(Tpm2PCRPredictionResult, result, 1);
3814 if (!copy)
3815 return log_oom();
3816
3817 r = ordered_set_ensure_put(context->results + pcr, &tpm2_pcr_prediction_result_hash_ops, copy);
3818 if (r == -EEXIST) /* Multiple identical results for the same PCR are totally expected */
3819 return 0;
3820 if (r < 0)
3821 return log_error_errno(r, "Failed to insert result into set: %m");
3822
3823 log_debug("Added prediction result %u for PCR %" PRIu32 " (path: %s)", ordered_set_size(context->results[pcr]), pcr, strempty(path));
3824
3825 TAKE_PTR(copy);
3826 return 0;
3827 }
3828
3829 static const EVP_MD* evp_from_tpm2_alg(uint16_t alg) {
3830 const char *name;
3831
3832 name = tpm2_hash_alg_to_string(alg);
3833 if (!name)
3834 return NULL;
3835
3836 return EVP_get_digestbyname(name);
3837 }
3838
3839 static int event_log_component_variant_calculate(
3840 Tpm2PCRPrediction *context,
3841 Tpm2PCRPredictionResult *result,
3842 EventLogComponent *component,
3843 EventLogComponentVariant *variant,
3844 uint32_t pcr,
3845 const char *path) {
3846
3847 int r;
3848
3849 assert(context);
3850 assert(result);
3851 assert(component);
3852 assert(variant);
3853
3854 FOREACH_ARRAY(rr, variant->records, variant->n_records) {
3855 EventLogRecord *rec = *rr;
3856
3857 if (rec->pcr != pcr)
3858 continue;
3859
3860 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
3861 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *md_ctx = NULL;
3862 EventLogRecordBank *b;
3863
3864 if (result->hash[i].size <= 0) /* already invalidated */
3865 continue;
3866
3867 b = event_log_record_find_bank(rec, tpm2_hash_algorithms[i]);
3868 if (!b) {
3869 /* Can't calculate, hence invalidate */
3870 result->hash[i] = (TPM2B_DIGEST) {};
3871 continue;
3872 }
3873
3874 md_ctx = EVP_MD_CTX_new();
3875 if (!md_ctx)
3876 return log_oom();
3877
3878 const EVP_MD *md = ASSERT_PTR(evp_from_tpm2_alg(tpm2_hash_algorithms[i]));
3879
3880 int sz = EVP_MD_size(md);
3881 assert(sz > 0);
3882 assert((size_t) sz <= sizeof_field(TPM2B_DIGEST, buffer));
3883
3884 assert(sz == tpm2_hash_alg_to_size(tpm2_hash_algorithms[i]));
3885
3886 assert(result->hash[i].size == (size_t) sz);
3887 assert(b->hash.size == (size_t) sz);
3888
3889 if (EVP_DigestInit_ex(md_ctx, md, NULL) != 1)
3890 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize message digest.");
3891
3892 if (EVP_DigestUpdate(md_ctx, result->hash[i].buffer, sz) != 1)
3893 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash bank value.");
3894
3895 if (EVP_DigestUpdate(md_ctx, b->hash.buffer, sz) != 1)
3896 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to hash data value.");
3897
3898 unsigned l = (unsigned) sz;
3899 if (EVP_DigestFinal_ex(md_ctx, result->hash[i].buffer, &l) != 1)
3900 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to finalize message digest.");
3901
3902 assert(l == (unsigned) sz);
3903 }
3904
3905 /* This is a valid result once we hit the start location */
3906 if (arg_location_start && strcmp(component->id, arg_location_start) >= 0) {
3907 r = pcr_prediction_add_result(context, result, pcr, path, rr - variant->records);
3908 if (r < 0)
3909 return r;
3910 }
3911 }
3912
3913 return 0;
3914 }
3915
3916 static int event_log_predict_pcrs(
3917 EventLog *el,
3918 Tpm2PCRPrediction *context,
3919 Tpm2PCRPredictionResult *parent_result,
3920 size_t component_index,
3921 uint32_t pcr,
3922 const char *path) {
3923
3924 EventLogComponent *component;
3925 int count = 0, r;
3926
3927 assert(el);
3928 assert(context);
3929 assert(parent_result);
3930
3931 /* Check if we reached the end of the components, generate a result, and backtrack */
3932 if (component_index >= el->n_components ||
3933 (arg_location_end && strcmp(el->components[component_index]->id, arg_location_end) > 0)) {
3934 r = pcr_prediction_add_result(context, parent_result, pcr, path, /* offset= */ 0);
3935 if (r < 0)
3936 return r;
3937
3938 return 1;
3939 }
3940
3941 component = ASSERT_PTR(el->components[component_index]);
3942
3943 FOREACH_ARRAY(ii, component->variants, component->n_variants) {
3944 _cleanup_free_ Tpm2PCRPredictionResult *result = NULL;
3945 EventLogComponentVariant *variant = *ii;
3946 _cleanup_free_ char *subpath = NULL;
3947
3948 /* Operate on a copy of the result */
3949
3950 if (path)
3951 subpath = strjoin(path, ":", component->id);
3952 else
3953 subpath = strdup(component->id);
3954 if (!subpath)
3955 return log_oom();
3956
3957 if (!streq(component->id, variant->id))
3958 if (!strextend(&subpath, "@", variant->id))
3959 return log_oom();
3960
3961 result = newdup(Tpm2PCRPredictionResult, parent_result, 1);
3962 if (!result)
3963 return log_oom();
3964
3965 r = event_log_component_variant_calculate(
3966 context,
3967 result,
3968 component,
3969 variant,
3970 pcr,
3971 subpath);
3972 if (r < 0)
3973 return r;
3974
3975 r = event_log_predict_pcrs(
3976 el,
3977 context,
3978 result,
3979 component_index + 1, /* Next component */
3980 pcr,
3981 subpath);
3982 if (r < 0)
3983 return r;
3984
3985 count += r;
3986 }
3987
3988 return count;
3989 }
3990
3991 static ssize_t event_log_calculate_component_combinations(EventLog *el) {
3992 ssize_t count = 1;
3993 assert(el);
3994
3995 FOREACH_ARRAY(cc, el->components, el->n_components) {
3996 EventLogComponent *c = *cc;
3997
3998 /* Overflow check */
3999 if (c->n_variants > (size_t) (SSIZE_MAX/count))
4000 return log_error_errno(SYNTHETIC_ERRNO(E2BIG), "Too many component combinations.");
4001
4002 count *= c->n_variants;
4003 }
4004
4005 return count;
4006 }
4007
4008 static int event_log_show_predictions(Tpm2PCRPrediction *context, uint16_t alg) {
4009 int r;
4010
4011 assert(context);
4012
4013 pager_open(arg_pager_flags);
4014
4015 if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) {
4016 _cleanup_(json_variant_unrefp) JsonVariant *j = NULL;
4017
4018 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++) {
4019 _cleanup_(json_variant_unrefp) JsonVariant *aj = NULL;
4020
4021 r = tpm2_pcr_prediction_to_json(
4022 context,
4023 tpm2_hash_algorithms[i],
4024 &aj);
4025 if (r < 0)
4026 return r;
4027
4028 if (json_variant_elements(aj) == 0)
4029 continue;
4030
4031 r = json_variant_set_field(
4032 &j,
4033 tpm2_hash_alg_to_string(tpm2_hash_algorithms[i]),
4034 aj);
4035 if (r < 0)
4036 return log_error_errno(r, "Failed to add prediction bank to object: %m");
4037 }
4038
4039 if (!j) {
4040 r = json_variant_new_object(&j, NULL, 0);
4041 if (r < 0)
4042 return log_error_errno(r, "Failed to allocated empty object: %m");
4043 }
4044
4045 json_variant_dump(j, arg_json_format_flags, /* f= */ NULL, /* prefix= */ NULL);
4046 return 0;
4047 }
4048
4049 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
4050 Tpm2PCRPredictionResult *result;
4051 if (!FLAGS_SET(context->pcrs, UINT32_C(1) << pcr))
4052 continue;
4053
4054 if (ordered_set_isempty(context->results[pcr])) {
4055 printf("No results for PCR %u (%s).\n", pcr, tpm2_pcr_index_to_string(pcr));
4056 continue;
4057 }
4058
4059 printf("%sResults for PCR %u (%s):%s\n", ansi_underline(), pcr, tpm2_pcr_index_to_string(pcr), ansi_normal());
4060
4061 ORDERED_SET_FOREACH(result, context->results[pcr]) {
4062
4063 _cleanup_free_ char *aa = NULL, *h = NULL;
4064 const char *a;
4065
4066 TPM2B_DIGEST *hash = tpm2_pcr_prediction_result_get_hash(result, alg);
4067 if (!hash)
4068 continue;
4069
4070 a = ASSERT_PTR(tpm2_hash_alg_to_string(alg));
4071 aa = strdup(a);
4072 if (!aa)
4073 return log_oom();
4074
4075 ascii_strlower(aa);
4076
4077 h = hexmem(hash->buffer, hash->size);
4078 if (!h)
4079 return log_oom();
4080
4081 printf(" %s%-6s:%s %s\n", ansi_grey(), aa, ansi_normal(), h);
4082 }
4083 }
4084
4085 return 0;
4086 }
4087
4088 static int tpm2_pcr_prediction_run(
4089 EventLog *el,
4090 Tpm2PCRPrediction *context) {
4091
4092 int r;
4093
4094 assert(el);
4095 assert(context);
4096
4097 for (uint32_t pcr = 0; pcr < TPM2_PCRS_MAX; pcr++) {
4098 _cleanup_free_ Tpm2PCRPredictionResult *result = NULL;
4099
4100 if (!FLAGS_SET(context->pcrs, UINT32_C(1) << pcr))
4101 continue;
4102
4103 result = new0(Tpm2PCRPredictionResult, 1);
4104 if (!result)
4105 return log_oom();
4106
4107 for (size_t i = 0; i < TPM2_N_HASH_ALGORITHMS; i++)
4108 event_log_initial_pcr_state(el, pcr, tpm2_hash_alg_to_size(tpm2_hash_algorithms[i]), result->hash + i);
4109
4110 r = event_log_predict_pcrs(
4111 el,
4112 context,
4113 result,
4114 /* component_index= */ 0,
4115 pcr,
4116 /* path= */ NULL);
4117 if (r < 0)
4118 return r;
4119 }
4120
4121 return 0;
4122 }
4123
4124 static int verb_predict(int argc, char *argv[], void *userdata) {
4125 _cleanup_(tpm2_pcr_prediction_done) Tpm2PCRPrediction context = {
4126 arg_pcr_mask != 0 ? arg_pcr_mask : DEFAULT_PCR_MASK,
4127 };
4128 _cleanup_(event_log_freep) EventLog *el = NULL;
4129 ssize_t count;
4130 int r;
4131
4132 r = event_log_load_and_process(&el);
4133 if (r < 0)
4134 return r;
4135
4136 count = event_log_calculate_component_combinations(el);
4137 if (count < 0)
4138 return count;
4139
4140 log_info("%zi combinations of components.", count);
4141
4142 r = event_log_reduce_to_safe_pcrs(el, &context.pcrs);
4143 if (r < 0)
4144 return r;
4145
4146 r = tpm2_pcr_prediction_run(el, &context);
4147 if (r < 0)
4148 return r;
4149
4150 return event_log_show_predictions(&context, el->primary_algorithm);
4151 }
4152
4153 static int remove_policy_file(const char *path) {
4154 assert(path);
4155
4156 if (unlink(path) < 0) {
4157 if (errno == ENOENT)
4158 return 0;
4159
4160 return log_error_errno(errno, "Failed to remove policy file '%s': %m", path);
4161 }
4162
4163 log_info("Removed policy file '%s'.", path);
4164 return 1;
4165 }
4166
4167 static int verb_make_policy(int argc, char *argv[], void *userdata) {
4168 int r;
4169
4170 /* Here's how this all works: after predicting all possible PCR values for next boot (with
4171 * alternatives) we'll calculate a policy from it as a combination of PolicyPCR + PolicyOR
4172 * expressions. This is then stored in an NV index. When a component of the boot process is changed a
4173 * new prediction is made and the NV index updated (which automatically invalidates any older
4174 * policies).
4175 *
4176 * Whenever we want to lock an encrypted object (for example FDE) against this policy, we'll use a
4177 * PolicyAuthorizeNV epxression that pins the NV index in the policy, and permits access to any
4178 * policies matching the current NV index contents.
4179 *
4180 * We grant world-readable read access to the NV index. Write access is controlled by a PIN (which we
4181 * either generate locally or which the user can provide us with) which can also be used for
4182 * recovery. This PIN is sealed to the TPM and is locked via PolicyAuthorizeNV to the NV index it
4183 * protects (i.e. we dogfood 🌭 🐶 hard here). This means in order to update such a policy we need
4184 * the policy to pass.
4185 *
4186 * Information about the used NV Index, the SRK of the TPM, the sealed PIN and the current PCR
4187 * prediction data are stored in a JSON file in /var/lib/. In order to be able to unlock root disks
4188 * this data must be also copied to the ESP so that it is available to the initrd. The data is not
4189 * sensitive, as SRK and NV index are pinned by it, and the prediction data must match the NV index
4190 * to be useful. */
4191
4192 usec_t start_usec = now(CLOCK_MONOTONIC);
4193
4194 _cleanup_(event_log_freep) EventLog *el = NULL;
4195 r = event_log_load_and_process(&el);
4196 if (r < 0)
4197 return r;
4198
4199 _cleanup_(tpm2_pcr_prediction_done) Tpm2PCRPrediction new_prediction = {
4200 arg_pcr_mask != 0 ? arg_pcr_mask : DEFAULT_PCR_MASK,
4201 };
4202 r = event_log_reduce_to_safe_pcrs(el, &new_prediction.pcrs);
4203 if (r < 0)
4204 return r;
4205
4206 usec_t predict_start_usec = now(CLOCK_MONOTONIC);
4207
4208 r = tpm2_pcr_prediction_run(el, &new_prediction);
4209 if (r < 0)
4210 return r;
4211
4212 log_info("Predicted future PCRs in %s.", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), predict_start_usec), 1));
4213
4214 _cleanup_(json_variant_unrefp) JsonVariant *new_prediction_json = NULL;
4215 r = tpm2_pcr_prediction_to_json(&new_prediction, el->primary_algorithm, &new_prediction_json);
4216 if (r < 0)
4217 return r;
4218
4219 if (DEBUG_LOGGING)
4220 (void) json_variant_dump(new_prediction_json, JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO, stderr, NULL);
4221
4222 _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy old_policy = {};
4223
4224 r = tpm2_pcrlock_policy_load(arg_pcrlock_path, &old_policy);
4225 if (r < 0)
4226 return r;
4227
4228 bool have_old_policy = r > 0;
4229
4230 /* When we update the policy the old serializations for NV, SRK, PIN remain the same */
4231 _cleanup_(iovec_done) struct iovec
4232 nv_blob = TAKE_STRUCT(old_policy.nv_handle),
4233 nv_public_blob = TAKE_STRUCT(old_policy.nv_public),
4234 srk_blob = TAKE_STRUCT(old_policy.srk_handle),
4235 pin_public = TAKE_STRUCT(old_policy.pin_public),
4236 pin_private = TAKE_STRUCT(old_policy.pin_private);
4237
4238 if (have_old_policy) {
4239 if (arg_nv_index != 0 && old_policy.nv_index != arg_nv_index)
4240 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Stored policy references different NV index (0x%x) than specified (0x%x), refusing.", old_policy.nv_index, arg_nv_index);
4241
4242 if (!arg_force &&
4243 old_policy.algorithm == el->primary_algorithm &&
4244 tpm2_pcr_prediction_equal(&old_policy.prediction, &new_prediction, el->primary_algorithm)) {
4245 log_info("Prediction is identical to current policy, skipping update.");
4246 return EXIT_SUCCESS;
4247 }
4248 }
4249
4250 _cleanup_(tpm2_context_unrefp) Tpm2Context *tc = NULL;
4251 r = tpm2_context_new(NULL, &tc);
4252 if (r < 0)
4253 return log_error_errno(r, "Failed to allocate TPM2 context: %m");
4254
4255 if (!tpm2_supports_command(tc, TPM2_CC_PolicyAuthorizeNV))
4256 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 does not support PolicyAuthorizeNV command, refusing.");
4257
4258 _cleanup_(tpm2_handle_freep) Tpm2Handle *srk_handle = NULL;
4259
4260 if (iovec_is_set(&srk_blob)) {
4261 r = tpm2_deserialize(
4262 tc,
4263 srk_blob.iov_base,
4264 srk_blob.iov_len,
4265 &srk_handle);
4266 if (r < 0)
4267 return log_error_errno(r, "Failed to deserialize SRK TR: %m");
4268 } else {
4269 r = tpm2_get_or_create_srk(
4270 tc,
4271 /* session= */ NULL,
4272 /* ret_public= */ NULL,
4273 /* ret_name= */ NULL,
4274 /* ret_qname= */ NULL,
4275 &srk_handle);
4276 if (r < 0)
4277 return log_error_errno(r, "Failed to install SRK: %m");
4278 }
4279
4280 _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
4281 r = tpm2_make_encryption_session(
4282 tc,
4283 srk_handle,
4284 /* bind_key= */ &TPM2_HANDLE_NONE,
4285 &encryption_session);
4286 if (r < 0)
4287 return log_error_errno(r, "Failed to allocate encryption session: %m");
4288
4289 /* Acquire a recovery PIN, either from the user, or create a randomized one */
4290 _cleanup_(erase_and_freep) char *pin = NULL;
4291 if (arg_recovery_pin) {
4292 r = getenv_steal_erase("PIN", &pin);
4293 if (r < 0)
4294 return log_error_errno(r, "Failed to acquire PIN from environment: %m");
4295 if (r == 0) {
4296 _cleanup_(strv_free_erasep) char **l = NULL;
4297
4298 r = ask_password_auto(
4299 "Recovery PIN",
4300 /* icon= */ NULL,
4301 /* id= */ "pcrlock-recovery-pin",
4302 /* key_name= */ NULL,
4303 /* credential_name= */ "systemd-pcrlock.recovery-pin",
4304 /* until= */ 0,
4305 /* flags= */ 0,
4306 &l);
4307 if (r < 0)
4308 return log_error_errno(r, "Failed to query for recovery PIN: %m");
4309
4310 if (strv_length(l) != 1)
4311 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected a single PIN only.");
4312
4313 pin = TAKE_PTR(l[0]);
4314 l = mfree(l);
4315 }
4316
4317 } else if (!have_old_policy) {
4318 char rnd[256];
4319
4320 r = crypto_random_bytes(rnd, sizeof(rnd));
4321 if (r < 0)
4322 return log_error_errno(r, "Failed to generate a randomized recovery PIN: %m");
4323
4324 (void) base64mem(rnd, sizeof(rnd), &pin);
4325 explicit_bzero_safe(rnd, sizeof(rnd));
4326 if (!pin)
4327 return log_oom();
4328 }
4329
4330 _cleanup_(tpm2_handle_freep) Tpm2Handle *nv_handle = NULL;
4331 TPM2_HANDLE nv_index = 0;
4332
4333 if (iovec_is_set(&nv_blob)) {
4334 r = tpm2_deserialize(tc, nv_blob.iov_base, nv_blob.iov_len, &nv_handle);
4335 if (r < 0)
4336 return log_error_errno(r, "Failed to deserialize NV index TR: %m");
4337
4338 nv_index = old_policy.nv_index;
4339 }
4340
4341 TPM2B_AUTH auth = {};
4342 CLEANUP_ERASE(auth);
4343
4344 if (pin) {
4345 r = tpm2_get_pin_auth(TPM2_ALG_SHA256, pin, &auth);
4346 if (r < 0)
4347 return log_error_errno(r, "Failed to hash PIN: %m");
4348 } else {
4349 assert(iovec_is_set(&pin_public));
4350 assert(iovec_is_set(&pin_private));
4351
4352 log_debug("Retrieving PIN from sealed data.");
4353
4354 usec_t pin_start_usec = now(CLOCK_MONOTONIC);
4355
4356 _cleanup_(iovec_done_erase) struct iovec secret = {};
4357 for (unsigned attempt = 0;; attempt++) {
4358 _cleanup_(tpm2_handle_freep) Tpm2Handle *policy_session = NULL;
4359
4360 r = tpm2_make_policy_session(
4361 tc,
4362 srk_handle,
4363 encryption_session,
4364 &policy_session);
4365 if (r < 0)
4366 return log_error_errno(r, "Failed to allocate policy session: %m");
4367
4368 r = tpm2_policy_super_pcr(
4369 tc,
4370 policy_session,
4371 &old_policy.prediction,
4372 old_policy.algorithm);
4373 if (r < 0)
4374 return log_error_errno(r, "Failed to submit super PCR policy: %m");
4375
4376 r = tpm2_policy_authorize_nv(
4377 tc,
4378 policy_session,
4379 nv_handle,
4380 NULL);
4381 if (r < 0)
4382 return log_error_errno(r, "Failed to submit AuthorizeNV policy: %m");
4383
4384 r = tpm2_unseal_data(
4385 tc,
4386 &pin_public,
4387 &pin_private,
4388 srk_handle,
4389 policy_session,
4390 encryption_session,
4391 &secret);
4392 if (r < 0 && (r != -ESTALE || attempt >= 16))
4393 return log_error_errno(r, "Failed to unseal PIN: %m");
4394 if (r == 0)
4395 break;
4396
4397 log_debug("Trying again (attempt %u), as PCR values changed during unlock attempt.", attempt+1);
4398 }
4399
4400 if (secret.iov_len > sizeof_field(TPM2B_AUTH, buffer))
4401 return log_error_errno(SYNTHETIC_ERRNO(E2BIG), "Decrypted PIN too large.");
4402
4403 auth = (TPM2B_AUTH) {
4404 .size = secret.iov_len,
4405 };
4406
4407 memcpy_safe(auth.buffer, secret.iov_base, secret.iov_len);
4408
4409 log_info("Retrieved PIN from TPM2 in %s.", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), pin_start_usec), 1));
4410 }
4411
4412 TPM2B_NV_PUBLIC nv_public = {};
4413
4414 usec_t nv_index_start_usec = now(CLOCK_MONOTONIC);
4415
4416 if (!iovec_is_set(&nv_blob)) {
4417 TPM2B_DIGEST recovery_policy_digest = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
4418 r = tpm2_calculate_policy_auth_value(&recovery_policy_digest);
4419 if (r < 0)
4420 return log_error_errno(r, "Failed to calculate authentication value policy: %m");
4421
4422 log_debug("Allocating NV index to write PCR policy to...");
4423 r = tpm2_define_policy_nv_index(
4424 tc,
4425 encryption_session,
4426 arg_nv_index,
4427 &recovery_policy_digest,
4428 pin,
4429 &auth,
4430 &nv_index,
4431 &nv_handle,
4432 &nv_public);
4433 if (r == -EEXIST)
4434 return log_error_errno(r, "NV index 0x%" PRIx32 " already allocated.", arg_nv_index);
4435 if (r < 0)
4436 return log_error_errno(r, "Failed to allocate NV index: %m");
4437 }
4438
4439 r = tpm2_set_auth_binary(tc, nv_handle, &auth);
4440 if (r < 0)
4441 return log_error_errno(r, "Failed to set authentication value on NV index: %m");
4442
4443 _cleanup_(tpm2_handle_freep) Tpm2Handle *policy_session = NULL;
4444 r = tpm2_make_policy_session(
4445 tc,
4446 srk_handle,
4447 encryption_session,
4448 &policy_session);
4449 if (r < 0)
4450 return log_error_errno(r, "Failed to allocate policy session: %m");
4451
4452 r = tpm2_policy_auth_value(
4453 tc,
4454 policy_session,
4455 /* ret_policy_digest= */ NULL);
4456 if (r < 0)
4457 return log_error_errno(r, "Failed to submit authentication value policy: %m");
4458
4459 log_debug("Calculating new PCR policy to write...");
4460 TPM2B_DIGEST new_super_pcr_policy_digest = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
4461
4462 usec_t pcr_policy_start_usec = now(CLOCK_MONOTONIC);
4463
4464 r = tpm2_calculate_policy_super_pcr(
4465 &new_prediction,
4466 el->primary_algorithm,
4467 &new_super_pcr_policy_digest);
4468 if (r < 0)
4469 return log_error_errno(r, "Failed to calculate super PCR policy: %m");
4470
4471 log_info("Calculated new PCR policy in %s.", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), pcr_policy_start_usec), 1));
4472
4473 log_debug("Writing new PCR policy to NV index...");
4474 r = tpm2_write_policy_nv_index(
4475 tc,
4476 policy_session,
4477 nv_index,
4478 nv_handle,
4479 &new_super_pcr_policy_digest);
4480 if (r < 0)
4481 return log_error_errno(r, "Failed to write to NV index: %m");
4482
4483 log_info("Updated NV index in %s.", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), nv_index_start_usec), 1));
4484
4485 assert(iovec_is_set(&pin_public) == iovec_is_set(&pin_private));
4486 if (!iovec_is_set(&pin_public)) {
4487 TPM2B_DIGEST authnv_policy_digest = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
4488
4489 r = tpm2_calculate_policy_authorize_nv(&nv_public, &authnv_policy_digest);
4490 if (r < 0)
4491 return log_error_errno(r, "Failed to calculate AuthorizeNV policy: %m");
4492
4493 struct iovec data = {
4494 .iov_base = auth.buffer,
4495 .iov_len = auth.size,
4496 };
4497
4498 usec_t pin_seal_start_usec = now(CLOCK_MONOTONIC);
4499
4500 log_debug("Sealing PIN to NV index policy...");
4501 r = tpm2_seal_data(
4502 tc,
4503 &data,
4504 srk_handle,
4505 encryption_session,
4506 &authnv_policy_digest,
4507 &pin_public,
4508 &pin_private);
4509 if (r < 0)
4510 return log_error_errno(r, "Failed to seal PIN to NV auth policy: %m");
4511
4512 log_info("Sealed PIN in %s.", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), pin_seal_start_usec), 1));
4513 }
4514
4515 if (!iovec_is_set(&nv_blob)) {
4516 r = tpm2_serialize(tc, nv_handle, &nv_blob.iov_base, &nv_blob.iov_len);
4517 if (r < 0)
4518 return log_error_errno(r, "Failed to serialize NV index TR: %m");
4519 }
4520
4521 if (!iovec_is_set(&srk_blob)) {
4522 r = tpm2_serialize(tc, srk_handle, &srk_blob.iov_base, &srk_blob.iov_len);
4523 if (r < 0)
4524 return log_error_errno(r, "Failed to serialize SRK index TR: %m");
4525 }
4526
4527 if (!iovec_is_set(&nv_public_blob)) {
4528 r = tpm2_marshal_nv_public(&nv_public, &nv_public_blob.iov_base, &nv_public_blob.iov_len);
4529 if (r < 0)
4530 return log_error_errno(r, "Failed to marshal NV public area: %m");
4531 }
4532
4533 _cleanup_(json_variant_unrefp) JsonVariant *new_configuration_json = NULL;
4534 r = json_build(&new_configuration_json,
4535 JSON_BUILD_OBJECT(
4536 JSON_BUILD_PAIR_STRING("pcrBank", tpm2_hash_alg_to_string(el->primary_algorithm)),
4537 JSON_BUILD_PAIR_VARIANT("pcrValues", new_prediction_json),
4538 JSON_BUILD_PAIR_INTEGER("nvIndex", nv_index),
4539 JSON_BUILD_PAIR_IOVEC_BASE64("nvHandle", &nv_blob),
4540 JSON_BUILD_PAIR_IOVEC_BASE64("nvPublic", &nv_public_blob),
4541 JSON_BUILD_PAIR_IOVEC_BASE64("srkHandle", &srk_blob),
4542 JSON_BUILD_PAIR_IOVEC_BASE64("pinPublic", &pin_public),
4543 JSON_BUILD_PAIR_IOVEC_BASE64("pinPrivate", &pin_private)));
4544 if (r < 0)
4545 return log_error_errno(r, "Failed to generate JSON: %m");
4546
4547 _cleanup_free_ char *text = NULL;
4548 r = json_variant_format(new_configuration_json, 0, &text);
4549 if (r < 0)
4550 return log_error_errno(r, "Failed to format new configuration to JSON: %m");
4551
4552 const char *path = arg_pcrlock_path ?: (in_initrd() ? "/run/systemd/pcrlock.json" : "/var/lib/systemd/pcrlock.json");
4553 r = write_string_file(path, text, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_SYNC|WRITE_STRING_FILE_MKDIR_0755);
4554 if (r < 0)
4555 return log_error_errno(r, "Failed to write new configuration to '%s': %m", path);
4556
4557 if (!arg_pcrlock_path && !in_initrd()) {
4558 r = remove_policy_file("/run/systemd/pcrlock.json");
4559 if (r < 0)
4560 return r;
4561 }
4562
4563 log_info("Written new policy to '%s' and digest to TPM2 NV index 0x%" PRIu32 ".", path, nv_index);
4564
4565 log_info("Overall time spent: %s", FORMAT_TIMESPAN(usec_sub_unsigned(now(CLOCK_MONOTONIC), start_usec), 1));
4566
4567 return 0;
4568 }
4569
4570 static int undefine_policy_nv_index(
4571 uint32_t nv_index,
4572 const struct iovec *nv_blob,
4573 const struct iovec *srk_blob) {
4574 int r;
4575
4576 assert(nv_blob);
4577 assert(srk_blob);
4578
4579 _cleanup_(tpm2_context_unrefp) Tpm2Context *tc = NULL;
4580 r = tpm2_context_new(NULL, &tc);
4581 if (r < 0)
4582 return r;
4583
4584 _cleanup_(tpm2_handle_freep) Tpm2Handle *srk_handle = NULL;
4585 r = tpm2_deserialize(
4586 tc,
4587 srk_blob->iov_base,
4588 srk_blob->iov_len,
4589 &srk_handle);
4590 if (r < 0)
4591 return log_error_errno(r, "Failed to deserialize SRK TR: %m");
4592
4593 _cleanup_(tpm2_handle_freep) Tpm2Handle *nv_handle = NULL;
4594 r = tpm2_deserialize(
4595 tc,
4596 nv_blob->iov_base,
4597 nv_blob->iov_len,
4598 &nv_handle);
4599 if (r < 0)
4600 return log_error_errno(r, "Failed to deserialize NV TR: %m");
4601
4602 _cleanup_(tpm2_handle_freep) Tpm2Handle *encryption_session = NULL;
4603 r = tpm2_make_encryption_session(
4604 tc,
4605 srk_handle,
4606 /* bind_key= */ &TPM2_HANDLE_NONE,
4607 &encryption_session);
4608 if (r < 0)
4609 return r;
4610
4611 r = tpm2_undefine_policy_nv_index(
4612 tc,
4613 encryption_session,
4614 nv_index,
4615 nv_handle);
4616 if (r < 0)
4617 return r;
4618
4619 log_info("Removed NV index 0x%x", nv_index);
4620 return 0;
4621 }
4622
4623 static int verb_remove_policy(int argc, char *argv[], void *userdata) {
4624 int r;
4625
4626 _cleanup_(tpm2_pcrlock_policy_done) Tpm2PCRLockPolicy policy = {};
4627 r = tpm2_pcrlock_policy_load(arg_policy_path, &policy);
4628 if (r == 0) {
4629 log_info("No policy found.");
4630 return 0;
4631 }
4632
4633 if (r < 0)
4634 log_notice("Failed to load old policy file, assuming it is corrupted, removing.");
4635 else {
4636 r = undefine_policy_nv_index(policy.nv_index, &policy.nv_handle, &policy.srk_handle);
4637 if (r < 0)
4638 log_notice("Failed to remove NV index, assuming data out of date, removing policy file.");
4639 }
4640
4641 if (arg_policy_path) {
4642 r = remove_policy_file(arg_policy_path);
4643 if (r < 0)
4644 return r;
4645
4646 return 0;
4647 } else {
4648 int ret = 0;
4649
4650 RET_GATHER(ret, remove_policy_file("/var/lib/systemd/pcrlock.json"));
4651 RET_GATHER(ret, remove_policy_file("/run/systemd/pcrlock.json"));
4652
4653 return ret;
4654 }
4655 }
4656
4657 static int help(int argc, char *argv[], void *userdata) {
4658 _cleanup_free_ char *link = NULL;
4659 int r;
4660
4661 r = terminal_urlify_man("systemd-pcrlock", "8", &link);
4662 if (r < 0)
4663 return log_oom();
4664
4665 printf("%1$s [OPTIONS...] COMMAND ...\n"
4666 "\n%5$sManage a TPM2 PCR lock.%6$s\n"
4667 "\n%3$sCommands:%4$s\n"
4668 " log Show measurement log\n"
4669 " cel Show measurement log in TCG CEL-JSON format\n"
4670 " list-components List defined .pcrlock components\n"
4671 " predict Predict PCR values\n"
4672 " make-policy Predict PCR values and generate TPM2 policy from it\n"
4673 " remove-policy Remove TPM2 policy\n"
4674 "\n%3$sProtections:%4$s\n"
4675 " lock-firmware-code Generate a .pcrlock file from current firmware code\n"
4676 " unlock-firmware-code Remove .pcrlock file for firmware code\n"
4677 " lock-firmware-config Generate a .pcrlock file from current firmware configuration\n"
4678 " unlock-firmware-config Remove .pcrlock file for firmware configuration\n"
4679 " lock-secureboot-policy Generate a .pcrlock file from current SecureBoot policy\n"
4680 " unlock-secureboot-policy Remove .pcrlock file for SecureBoot policy\n"
4681 " lock-secureboot-authority Generate a .pcrlock file from current SecureBoot authority\n"
4682 " unlock-secureboot-authority Remove .pcrlock file for SecureBoot authority\n"
4683 " lock-gpt [DISK] Generate a .pcrlock file from GPT header\n"
4684 " unlock-gpt Remove .pcrlock file for GPT header\n"
4685 " lock-pe [BINARY] Generate a .pcrlock file from PE binary\n"
4686 " unlock-pe Remove .pcrlock file for PE binary\n"
4687 " lock-uki [UKI] Generate a .pcrlock file from UKI PE binary\n"
4688 " unlock-uki Remove .pcrlock file for UKI PE binary\n"
4689 " lock-machine-id Generate a .pcrlock file from current machine ID\n"
4690 " unlock-machine-id Remove .pcrlock file for machine ID\n"
4691 " lock-file-system [PATH] Generate a .pcrlock file from current root fs + /var/\n"
4692 " unlock-file-system [PATH] Remove .pcrlock file for root fs + /var/\n"
4693 " lock-kernel-cmdline [FILE] Generate a .pcrlock file from kernel command line\n"
4694 " unlock-kernel-cmdline Remove .pcrlock file for kernel command line\n"
4695 " lock-kernel-initrd FILE Generate a .pcrlock file from an initrd file\n"
4696 " unlock-kernel-initrd Remove .pcrlock file for an initrd file\n"
4697 " lock-raw [FILE] Generate a .pcrlock file from raw data\n"
4698 " unlock-raw Remove .pcrlock file for raw data\n"
4699 "\n%3$sOptions:%4$s\n"
4700 " -h --help Show this help\n"
4701 " --version Print version\n"
4702 " --no-pager Do not pipe output into a pager\n"
4703 " --json=pretty|short|off Generate JSON output\n"
4704 " --raw-description Show raw firmware record data as description in table\n"
4705 " --pcr=NR Generate .pcrlock for specified PCR\n"
4706 " --nv-index=NUMBER Use the specified NV index, instead of a random one\n"
4707 " --components=PATH Directory to read .pcrlock files from\n"
4708 " --location=STRING[:STRING]\n"
4709 " Do not process components beyond this component name\n"
4710 " --recovery-pin=yes Ask for a recovery PIN\n"
4711 " --pcrlock=PATH .pcrlock file to write expected PCR measurement to\n"
4712 " --policy=PATH JSON file to write policy output to\n"
4713 " --force Write policy even if it matches existing policy\n"
4714 "\nSee the %2$s for details.\n",
4715 program_invocation_short_name,
4716 link,
4717 ansi_underline(),
4718 ansi_normal(),
4719 ansi_highlight(),
4720 ansi_normal());
4721
4722 return 0;
4723 }
4724
4725 static int parse_argv(int argc, char *argv[]) {
4726 enum {
4727 ARG_VERSION = 0x100,
4728 ARG_NO_PAGER,
4729 ARG_JSON,
4730 ARG_RAW_DESCRIPTION,
4731 ARG_PCR,
4732 ARG_NV_INDEX,
4733 ARG_COMPONENTS,
4734 ARG_LOCATION,
4735 ARG_RECOVERY_PIN,
4736 ARG_PCRLOCK,
4737 ARG_POLICY,
4738 ARG_FORCE,
4739 };
4740
4741 static const struct option options[] = {
4742 { "help", no_argument, NULL, 'h' },
4743 { "version", no_argument, NULL, ARG_VERSION },
4744 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
4745 { "json", required_argument, NULL, ARG_JSON },
4746 { "raw-description", no_argument, NULL, ARG_RAW_DESCRIPTION },
4747 { "pcr", required_argument, NULL, ARG_PCR },
4748 { "nv-index", required_argument, NULL, ARG_NV_INDEX },
4749 { "components", required_argument, NULL, ARG_COMPONENTS },
4750 { "location", required_argument, NULL, ARG_LOCATION },
4751 { "recovery-pin", required_argument, NULL, ARG_RECOVERY_PIN },
4752 { "pcrlock", required_argument, NULL, ARG_PCRLOCK },
4753 { "policy", required_argument, NULL, ARG_POLICY },
4754 { "force", no_argument, NULL, ARG_FORCE },
4755 {}
4756 };
4757
4758 bool auto_location = true;
4759 int c, r;
4760
4761 assert(argc >= 0);
4762 assert(argv);
4763
4764 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
4765 switch (c) {
4766
4767 case 'h':
4768 help(0, NULL, NULL);
4769 return 0;
4770
4771 case ARG_VERSION:
4772 return version();
4773
4774 case ARG_NO_PAGER:
4775 arg_pager_flags |= PAGER_DISABLE;
4776 break;
4777
4778 case ARG_JSON:
4779 r = parse_json_argument(optarg, &arg_json_format_flags);
4780 if (r <= 0)
4781 return r;
4782 break;
4783
4784 case ARG_RAW_DESCRIPTION:
4785 arg_raw_description = true;
4786 break;
4787
4788 case ARG_PCR: {
4789 r = tpm2_parse_pcr_argument_to_mask(optarg, &arg_pcr_mask);
4790 if (r < 0)
4791 return log_error_errno(r, "Failed to parse PCR specification: %s", optarg);
4792
4793 break;
4794 }
4795
4796 case ARG_NV_INDEX:
4797 if (isempty(optarg))
4798 arg_nv_index = 0;
4799 else {
4800 uint32_t u;
4801
4802 r = safe_atou32_full(optarg, 16, &u);
4803 if (r < 0)
4804 return log_error_errno(r, "Failed to parse --nv-index= argument: %s", optarg);
4805
4806 if (u < TPM2_NV_INDEX_FIRST || u > TPM2_NV_INDEX_LAST)
4807 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Argument for --nv-index= outside of valid range 0x%" PRIx32 "…0x%" PRIx32 ": 0x%" PRIx32,
4808 TPM2_NV_INDEX_FIRST, TPM2_NV_INDEX_LAST, u);
4809
4810 arg_nv_index = u;
4811 }
4812 break;
4813
4814 case ARG_COMPONENTS: {
4815 _cleanup_free_ char *p = NULL;
4816
4817 r = parse_path_argument(optarg, /* suppress_root= */ false, &p);
4818 if (r < 0)
4819 return r;
4820
4821 r = strv_consume(&arg_components, TAKE_PTR(p));
4822 if (r < 0)
4823 return log_oom();
4824
4825 break;
4826 }
4827
4828 case ARG_LOCATION: {
4829 _cleanup_free_ char *start = NULL, *end = NULL;
4830 const char *e;
4831
4832 auto_location = false;
4833
4834 if (isempty(optarg)) {
4835 arg_location_start = mfree(arg_location_start);
4836 arg_location_end = mfree(arg_location_end);
4837 break;
4838 }
4839
4840 e = strchr(optarg, ':');
4841 if (e) {
4842 start = strndup(optarg, e - optarg);
4843 if (!start)
4844 return log_oom();
4845
4846 end = strdup(e + 1);
4847 if (!end)
4848 return log_oom();
4849 } else {
4850 start = strdup(optarg);
4851 if (!start)
4852 return log_oom();
4853
4854 end = strdup(optarg);
4855 if (!end)
4856 return log_oom();
4857 }
4858
4859 if (!filename_is_valid(start))
4860 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Location string invalid, refusing: %s", start);
4861 if (!filename_is_valid(end))
4862 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Location string invalid, refusing: %s", end);
4863
4864 free_and_replace(arg_location_start, start);
4865 free_and_replace(arg_location_end, end);
4866 break;
4867 }
4868
4869 case ARG_RECOVERY_PIN:
4870 r = parse_boolean_argument("--recovery-pin", optarg, &arg_recovery_pin);
4871 if (r < 0)
4872 return r;
4873 break;
4874
4875 case ARG_PCRLOCK:
4876 if (empty_or_dash(optarg))
4877 arg_pcrlock_path = mfree(arg_pcrlock_path);
4878 else {
4879 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_pcrlock_path);
4880 if (r < 0)
4881 return r;
4882 }
4883
4884 arg_pcrlock_auto = false;
4885 break;
4886
4887 case ARG_POLICY:
4888 if (empty_or_dash(optarg))
4889 arg_policy_path = mfree(arg_policy_path);
4890 else {
4891 r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_policy_path);
4892 if (r < 0)
4893 return r;
4894 }
4895
4896 break;
4897
4898 case ARG_FORCE:
4899 arg_force = true;
4900 break;
4901
4902 case '?':
4903 return -EINVAL;
4904
4905 default:
4906 assert_not_reached();
4907 }
4908
4909 if (auto_location) {
4910 assert(!arg_location_start);
4911 assert(!arg_location_end);
4912
4913 arg_location_start = strdup("760-");
4914 if (!arg_location_start)
4915 return log_oom();
4916
4917 arg_location_end = strdup("940-");
4918 if (!arg_location_end)
4919 return log_oom();
4920 }
4921
4922 return 1;
4923 }
4924
4925 static int pcrlock_main(int argc, char *argv[]) {
4926 static const Verb verbs[] = {
4927 { "help", VERB_ANY, VERB_ANY, 0, help },
4928 { "log", VERB_ANY, 1, VERB_DEFAULT, verb_show_log },
4929 { "cel", VERB_ANY, 1, 0, verb_show_cel },
4930 { "list-components", VERB_ANY, 1, 0, verb_list_components },
4931 { "predict", VERB_ANY, 1, 0, verb_predict },
4932 { "lock-firmware-code", VERB_ANY, 2, 0, verb_lock_firmware },
4933 { "unlock-firmware-code", VERB_ANY, 1, 0, verb_unlock_firmware },
4934 { "lock-firmware-config", VERB_ANY, 2, 0, verb_lock_firmware },
4935 { "unlock-firmware-config", VERB_ANY, 1, 0, verb_unlock_firmware },
4936 { "lock-secureboot-policy", VERB_ANY, 1, 0, verb_lock_secureboot_policy },
4937 { "unlock-secureboot-policy", VERB_ANY, 1, 0, verb_unlock_secureboot_policy },
4938 { "lock-secureboot-authority", VERB_ANY, 1, 0, verb_lock_secureboot_authority },
4939 { "unlock-secureboot-authority", VERB_ANY, 1, 0, verb_unlock_secureboot_authority },
4940 { "lock-gpt", VERB_ANY, 2, 0, verb_lock_gpt },
4941 { "unlock-gpt", VERB_ANY, 1, 0, verb_unlock_gpt },
4942 { "lock-pe", VERB_ANY, 2, 0, verb_lock_pe },
4943 { "unlock-pe", VERB_ANY, 1, 0, verb_unlock_simple },
4944 { "lock-uki", VERB_ANY, 2, 0, verb_lock_uki },
4945 { "unlock-uki", VERB_ANY, 1, 0, verb_unlock_simple },
4946 { "lock-machine-id", VERB_ANY, 1, 0, verb_lock_machine_id },
4947 { "unlock-machine-id", VERB_ANY, 1, 0, verb_unlock_machine_id },
4948 { "lock-file-system", VERB_ANY, 2, 0, verb_lock_file_system },
4949 { "unlock-file-system", VERB_ANY, 2, 0, verb_unlock_file_system },
4950 { "lock-kernel-cmdline", VERB_ANY, 2, 0, verb_lock_kernel_cmdline },
4951 { "unlock-kernel-cmdline", VERB_ANY, 1, 0, verb_unlock_kernel_cmdline },
4952 { "lock-kernel-initrd", VERB_ANY, 2, 0, verb_lock_kernel_initrd },
4953 { "unlock-kernel-initrd", VERB_ANY, 1, 0, verb_unlock_kernel_initrd },
4954 { "lock-raw", VERB_ANY, 2, 0, verb_lock_raw },
4955 { "unlock-raw", VERB_ANY, 1, 0, verb_unlock_simple },
4956 { "make-policy", VERB_ANY, 1, 0, verb_make_policy },
4957 { "remove-policy", VERB_ANY, 1, 0, verb_remove_policy },
4958 {}
4959 };
4960
4961 return dispatch_verb(argc, argv, verbs, NULL);
4962 }
4963
4964 static int run(int argc, char *argv[]) {
4965 int r;
4966
4967 log_show_color(true);
4968 log_parse_environment();
4969 log_open();
4970
4971 r = parse_argv(argc, argv);
4972 if (r <= 0)
4973 return r;
4974
4975 return pcrlock_main(argc, argv);
4976 }
4977
4978 DEFINE_MAIN_FUNCTION(run);