1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #if ENABLE_TPM
4
5 #include <efi.h>
6 #include <efilib.h>
7
8 #include "macro-fundamental.h"
9 #include "measure.h"
10 #include "missing_efi.h"
11 #include "util.h"
12
tpm1_measure_to_pcr_and_event_log(const EFI_TCG * tcg,UINT32 pcrindex,EFI_PHYSICAL_ADDRESS buffer,UINTN buffer_size,const CHAR16 * description)13 static EFI_STATUS tpm1_measure_to_pcr_and_event_log(
14 const EFI_TCG *tcg,
15 UINT32 pcrindex,
16 EFI_PHYSICAL_ADDRESS buffer,
17 UINTN buffer_size,
18 const CHAR16 *description) {
19
20 _cleanup_freepool_ TCG_PCR_EVENT *tcg_event = NULL;
21 EFI_PHYSICAL_ADDRESS event_log_last;
22 UINT32 event_number = 1;
23 UINTN desc_len;
24
25 assert(tcg);
26 assert(description);
27
28 desc_len = StrSize(description);
29 tcg_event = xallocate_zero_pool(offsetof(TCG_PCR_EVENT, Event) + desc_len);
30 *tcg_event = (TCG_PCR_EVENT) {
31 .EventSize = desc_len,
32 .PCRIndex = pcrindex,
33 .EventType = EV_IPL,
34 };
35 CopyMem(tcg_event->Event, description, desc_len);
36
37 return tcg->HashLogExtendEvent(
38 (EFI_TCG *) tcg,
39 buffer, buffer_size,
40 TCG_ALG_SHA,
41 tcg_event,
42 &event_number,
43 &event_log_last);
44 }
45
tpm2_measure_to_pcr_and_event_log(EFI_TCG2 * tcg,UINT32 pcrindex,EFI_PHYSICAL_ADDRESS buffer,UINT64 buffer_size,const CHAR16 * description)46 static EFI_STATUS tpm2_measure_to_pcr_and_event_log(
47 EFI_TCG2 *tcg,
48 UINT32 pcrindex,
49 EFI_PHYSICAL_ADDRESS buffer,
50 UINT64 buffer_size,
51 const CHAR16 *description) {
52
53 _cleanup_freepool_ EFI_TCG2_EVENT *tcg_event = NULL;
54 UINTN desc_len;
55
56 assert(tcg);
57 assert(description);
58
59 desc_len = StrSize(description);
60 tcg_event = xallocate_zero_pool(offsetof(EFI_TCG2_EVENT, Event) + desc_len);
61 *tcg_event = (EFI_TCG2_EVENT) {
62 .Size = offsetof(EFI_TCG2_EVENT, Event) + desc_len,
63 .Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER),
64 .Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION,
65 .Header.PCRIndex = pcrindex,
66 .Header.EventType = EV_IPL,
67 };
68
69 CopyMem(tcg_event->Event, description, desc_len);
70
71 return tcg->HashLogExtendEvent(
72 tcg,
73 0,
74 buffer, buffer_size,
75 tcg_event);
76 }
77
tcg1_interface_check(void)78 static EFI_TCG *tcg1_interface_check(void) {
79 EFI_PHYSICAL_ADDRESS event_log_location, event_log_last_entry;
80 TCG_BOOT_SERVICE_CAPABILITY capability = {
81 .Size = sizeof(capability),
82 };
83 EFI_STATUS status;
84 UINT32 features;
85 EFI_TCG *tcg;
86
87 status = LibLocateProtocol((EFI_GUID*) EFI_TCG_GUID, (void **) &tcg);
88 if (EFI_ERROR(status))
89 return NULL;
90
91 status = tcg->StatusCheck(
92 tcg,
93 &capability,
94 &features,
95 &event_log_location,
96 &event_log_last_entry);
97 if (EFI_ERROR(status))
98 return NULL;
99
100 if (capability.TPMDeactivatedFlag)
101 return NULL;
102
103 if (!capability.TPMPresentFlag)
104 return NULL;
105
106 return tcg;
107 }
108
tcg2_interface_check(void)109 static EFI_TCG2 * tcg2_interface_check(void) {
110 EFI_TCG2_BOOT_SERVICE_CAPABILITY capability = {
111 .Size = sizeof(capability),
112 };
113 EFI_STATUS status;
114 EFI_TCG2 *tcg;
115
116 status = LibLocateProtocol((EFI_GUID*) EFI_TCG2_GUID, (void **) &tcg);
117 if (EFI_ERROR(status))
118 return NULL;
119
120 status = tcg->GetCapability(tcg, &capability);
121 if (EFI_ERROR(status))
122 return NULL;
123
124 if (capability.StructureVersion.Major == 1 &&
125 capability.StructureVersion.Minor == 0) {
126 TCG_BOOT_SERVICE_CAPABILITY *caps_1_0 =
127 (TCG_BOOT_SERVICE_CAPABILITY*) &capability;
128 if (caps_1_0->TPMPresentFlag)
129 return tcg;
130 }
131
132 if (!capability.TPMPresentFlag)
133 return NULL;
134
135 return tcg;
136 }
137
tpm_present(void)138 BOOLEAN tpm_present(void) {
139 return tcg2_interface_check() || tcg1_interface_check();
140 }
141
tpm_log_event(UINT32 pcrindex,EFI_PHYSICAL_ADDRESS buffer,UINTN buffer_size,const CHAR16 * description)142 EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
143 EFI_TCG *tpm1;
144 EFI_TCG2 *tpm2;
145
146 assert(description);
147
148 /* PCR disabled */
149 if (pcrindex == UINT32_MAX)
150 return EFI_SUCCESS;
151
152 tpm2 = tcg2_interface_check();
153 if (tpm2)
154 return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
155
156 tpm1 = tcg1_interface_check();
157 if (tpm1)
158 return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
159
160 /* No active TPM found, so don't return an error */
161 return EFI_SUCCESS;
162 }
163
tpm_log_load_options(const CHAR16 * load_options)164 EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) {
165 EFI_STATUS err;
166
167 /* Measures a load options string into the TPM2, i.e. the kernel command line */
168
169 for (UINTN i = 0; i < 2; i++) {
170 UINT32 pcr = i == 0 ? TPM_PCR_INDEX_KERNEL_PARAMETERS : TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT;
171
172 err = tpm_log_event(pcr,
173 POINTER_TO_PHYSICAL_ADDRESS(load_options),
174 StrSize(load_options), load_options);
175 if (EFI_ERROR(err))
176 return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err);
177 }
178
179 return EFI_SUCCESS;
180 }
181
182 #endif
183