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