]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
92ed3bb4 | 2 | |
349cc4a5 | 3 | #if ENABLE_TPM |
92ed3bb4 | 4 | |
508df915 | 5 | #include "macro-fundamental.h" |
92ed3bb4 | 6 | #include "measure.h" |
4ac79c2b | 7 | #include "memory-util-fundamental.h" |
7ff0e0a5 | 8 | #include "proto/cc-measurement.h" |
5080a60a | 9 | #include "proto/tcg.h" |
e0e1f4f7 | 10 | #include "tpm2-pcr.h" |
ff3aa8d1 | 11 | #include "util.h" |
92ed3bb4 | 12 | |
d869ec4a LB |
13 | static EFI_STATUS tpm2_measure_to_pcr_and_tagged_event_log( |
14 | EFI_TCG2_PROTOCOL *tcg, | |
15 | uint32_t pcrindex, | |
16 | EFI_PHYSICAL_ADDRESS buffer, | |
17 | uint64_t buffer_size, | |
18 | uint32_t event_id, | |
19 | const char16_t *description) { | |
20 | ||
21 | _cleanup_free_ struct event { | |
22 | EFI_TCG2_EVENT tcg_event; | |
23 | EFI_TCG2_TAGGED_EVENT tcg_tagged_event; | |
24 | } _packed_ *event = NULL; | |
25 | size_t desc_len, event_size; | |
26 | ||
27 | assert(tcg); | |
28 | assert(description); | |
29 | ||
30 | desc_len = strsize16(description); | |
31 | event_size = offsetof(EFI_TCG2_EVENT, Event) + offsetof(EFI_TCG2_TAGGED_EVENT, Event) + desc_len; | |
32 | ||
586f1997 | 33 | event = xmalloc(event_size); |
d869ec4a LB |
34 | *event = (struct event) { |
35 | .tcg_event = (EFI_TCG2_EVENT) { | |
36 | .Size = event_size, | |
37 | .Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER), | |
38 | .Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION, | |
39 | .Header.PCRIndex = pcrindex, | |
40 | .Header.EventType = EV_EVENT_TAG, | |
41 | }, | |
42 | .tcg_tagged_event = { | |
43 | .EventId = event_id, | |
44 | .EventSize = desc_len, | |
45 | }, | |
46 | }; | |
47 | memcpy(event->tcg_tagged_event.Event, description, desc_len); | |
48 | ||
49 | return tcg->HashLogExtendEvent( | |
50 | tcg, | |
51 | 0, | |
52 | buffer, buffer_size, | |
53 | &event->tcg_event); | |
54 | } | |
55 | ||
ff3aa8d1 | 56 | static EFI_STATUS tpm2_measure_to_pcr_and_event_log( |
5080a60a | 57 | EFI_TCG2_PROTOCOL *tcg, |
db4122d1 | 58 | uint32_t pcrindex, |
ff3aa8d1 | 59 | EFI_PHYSICAL_ADDRESS buffer, |
db4122d1 | 60 | uint64_t buffer_size, |
3639d1b0 | 61 | const char16_t *description) { |
ff3aa8d1 | 62 | |
93521e55 | 63 | _cleanup_free_ EFI_TCG2_EVENT *tcg_event = NULL; |
dede50a7 | 64 | size_t desc_len; |
92ed3bb4 | 65 | |
508df915 JJ |
66 | assert(tcg); |
67 | assert(description); | |
68 | ||
b022ea04 LP |
69 | /* NB: We currently record everything as EV_IPL. Which sucks, because it makes it hard to |
70 | * recognize from the event log which of the events are ours. Measurement logs are kinda API hence | |
71 | * this is hard to change for existing, established events. But for future additions, let's use | |
72 | * EV_EVENT_TAG instead, with a tag of our choosing that makes clear what precisely we are measuring | |
73 | * here. */ | |
74 | ||
60c2af56 | 75 | desc_len = strsize16(description); |
586f1997 | 76 | tcg_event = xmalloc(offsetof(EFI_TCG2_EVENT, Event) + desc_len); |
ff3aa8d1 | 77 | *tcg_event = (EFI_TCG2_EVENT) { |
7700e9ba | 78 | .Size = offsetof(EFI_TCG2_EVENT, Event) + desc_len, |
ff3aa8d1 LP |
79 | .Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER), |
80 | .Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION, | |
81 | .Header.PCRIndex = pcrindex, | |
82 | .Header.EventType = EV_IPL, | |
83 | }; | |
84 | ||
bbc1f2ea | 85 | memcpy(tcg_event->Event, description, desc_len); |
ff3aa8d1 | 86 | |
12f32748 | 87 | return tcg->HashLogExtendEvent( |
ff3aa8d1 LP |
88 | tcg, |
89 | 0, | |
90 | buffer, buffer_size, | |
91 | tcg_event); | |
92ed3bb4 HH |
92 | } |
93 | ||
7ff0e0a5 MY |
94 | static EFI_STATUS cc_measure_to_mr_and_event_log( |
95 | EFI_CC_MEASUREMENT_PROTOCOL *cc, | |
96 | uint32_t pcrindex, | |
97 | EFI_PHYSICAL_ADDRESS buffer, | |
98 | uint64_t buffer_size, | |
99 | const char16_t *description) { | |
100 | ||
101 | _cleanup_free_ EFI_CC_EVENT *event = NULL; | |
102 | uint32_t mr; | |
103 | EFI_STATUS err; | |
104 | size_t desc_len; | |
105 | ||
106 | assert(cc); | |
107 | assert(description); | |
108 | ||
109 | /* MapPcrToMrIndex service provides callers information on | |
110 | * how the TPM PCR registers are mapped to the CC measurement | |
111 | * registers (MR) in the vendor implementation. */ | |
112 | err = cc->MapPcrToMrIndex(cc, pcrindex, &mr); | |
113 | if (err != EFI_SUCCESS) | |
114 | return EFI_NOT_FOUND; | |
115 | ||
116 | desc_len = strsize16(description); | |
117 | event = xmalloc(offsetof(EFI_CC_EVENT, Event) + desc_len); | |
118 | *event = (EFI_CC_EVENT) { | |
119 | .Size = offsetof(EFI_CC_EVENT, Event) + desc_len, | |
120 | .Header.HeaderSize = sizeof(EFI_CC_EVENT_HEADER), | |
121 | .Header.HeaderVersion = EFI_CC_EVENT_HEADER_VERSION, | |
122 | .Header.MrIndex = mr, | |
123 | .Header.EventType = EV_IPL, | |
124 | }; | |
125 | ||
126 | memcpy(event->Event, description, desc_len); | |
127 | ||
128 | return cc->HashLogExtendEvent( | |
129 | cc, | |
130 | 0, | |
131 | buffer, | |
132 | buffer_size, | |
133 | event); | |
134 | } | |
135 | ||
136 | static EFI_CC_MEASUREMENT_PROTOCOL *cc_interface_check(void) { | |
137 | EFI_CC_BOOT_SERVICE_CAPABILITY capability = { | |
138 | .Size = sizeof(capability), | |
139 | }; | |
140 | EFI_STATUS err; | |
141 | EFI_CC_MEASUREMENT_PROTOCOL *cc; | |
142 | ||
143 | err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_CC_MEASUREMENT_PROTOCOL), NULL, (void **) &cc); | |
144 | if (err != EFI_SUCCESS) | |
145 | return NULL; | |
146 | ||
147 | err = cc->GetCapability(cc, &capability); | |
148 | if (err != EFI_SUCCESS) | |
149 | return NULL; | |
150 | ||
151 | if (!(capability.SupportedEventLogs & EFI_CC_EVENT_LOG_FORMAT_TCG_2)) | |
152 | return NULL; | |
153 | ||
154 | return cc; | |
155 | } | |
156 | ||
5080a60a | 157 | static EFI_TCG2_PROTOCOL *tcg2_interface_check(void) { |
ff3aa8d1 LP |
158 | EFI_TCG2_BOOT_SERVICE_CAPABILITY capability = { |
159 | .Size = sizeof(capability), | |
160 | }; | |
8599bdb6 | 161 | EFI_STATUS err; |
5080a60a | 162 | EFI_TCG2_PROTOCOL *tcg; |
92ed3bb4 | 163 | |
5080a60a | 164 | err = BS->LocateProtocol(MAKE_GUID_PTR(EFI_TCG2_PROTOCOL), NULL, (void **) &tcg); |
2a5e4fe4 | 165 | if (err != EFI_SUCCESS) |
92ed3bb4 HH |
166 | return NULL; |
167 | ||
8599bdb6 | 168 | err = tcg->GetCapability(tcg, &capability); |
2a5e4fe4 | 169 | if (err != EFI_SUCCESS) |
92ed3bb4 HH |
170 | return NULL; |
171 | ||
f8e54bf3 JR |
172 | if (capability.StructureVersion.Major == 1 && |
173 | capability.StructureVersion.Minor == 0) { | |
5080a60a JJ |
174 | EFI_TCG_BOOT_SERVICE_CAPABILITY *caps_1_0 = |
175 | (EFI_TCG_BOOT_SERVICE_CAPABILITY*) &capability; | |
bfdf8c3b HH |
176 | if (caps_1_0->TPMPresentFlag) |
177 | return tcg; | |
178 | } | |
179 | ||
f8e54bf3 | 180 | if (!capability.TPMPresentFlag) |
92ed3bb4 HH |
181 | return NULL; |
182 | ||
183 | return tcg; | |
184 | } | |
185 | ||
e5a1b8f9 | 186 | bool tpm_present(void) { |
13fc754d | 187 | return tcg2_interface_check(); |
a87e9cd7 JJ |
188 | } |
189 | ||
dede50a7 | 190 | EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char16_t *description, bool *ret_measured) { |
5080a60a | 191 | EFI_TCG2_PROTOCOL *tpm2; |
8d5e4d59 | 192 | EFI_STATUS err; |
bfdf8c3b | 193 | |
f92428ea | 194 | assert(description || pcrindex == UINT32_MAX); |
508df915 | 195 | |
8d5e4d59 LP |
196 | /* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured |
197 | * something, or false if measurement was turned off. */ | |
198 | ||
199 | if (pcrindex == UINT32_MAX) { /* PCR disabled? */ | |
200 | if (ret_measured) | |
201 | *ret_measured = false; | |
202 | ||
4d32507f | 203 | return EFI_SUCCESS; |
8d5e4d59 | 204 | } |
4d32507f | 205 | |
f8e54bf3 | 206 | tpm2 = tcg2_interface_check(); |
38cd55b0 | 207 | if (tpm2) |
8d5e4d59 LP |
208 | err = tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); |
209 | else { | |
13fc754d | 210 | EFI_CC_MEASUREMENT_PROTOCOL *cc; |
92ed3bb4 | 211 | |
13fc754d LP |
212 | cc = cc_interface_check(); |
213 | if (cc) | |
214 | err = cc_measure_to_mr_and_event_log(cc, pcrindex, buffer, buffer_size, description); | |
8d5e4d59 | 215 | else { |
13fc754d | 216 | /* No active TPM found, so don't return an error */ |
92ed3bb4 | 217 | |
13fc754d LP |
218 | if (ret_measured) |
219 | *ret_measured = false; | |
8d5e4d59 | 220 | |
13fc754d | 221 | return EFI_SUCCESS; |
8d5e4d59 LP |
222 | } |
223 | } | |
224 | ||
225 | if (err == EFI_SUCCESS && ret_measured) | |
226 | *ret_measured = true; | |
227 | ||
228 | return err; | |
229 | } | |
230 | ||
d869ec4a LB |
231 | EFI_STATUS tpm_log_tagged_event( |
232 | uint32_t pcrindex, | |
233 | EFI_PHYSICAL_ADDRESS buffer, | |
234 | size_t buffer_size, | |
235 | uint32_t event_id, | |
236 | const char16_t *description, | |
237 | bool *ret_measured) { | |
238 | ||
239 | EFI_TCG2_PROTOCOL *tpm2; | |
240 | EFI_STATUS err; | |
241 | ||
242 | assert(description || pcrindex == UINT32_MAX); | |
243 | assert(event_id > 0); | |
244 | ||
245 | /* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured | |
246 | * something, or false if measurement was turned off. */ | |
247 | ||
248 | tpm2 = tcg2_interface_check(); | |
249 | if (!tpm2 || pcrindex == UINT32_MAX) { /* PCR disabled? */ | |
250 | if (ret_measured) | |
251 | *ret_measured = false; | |
252 | ||
253 | return EFI_SUCCESS; | |
254 | } | |
255 | ||
256 | err = tpm2_measure_to_pcr_and_tagged_event_log(tpm2, pcrindex, buffer, buffer_size, event_id, description); | |
257 | if (err == EFI_SUCCESS && ret_measured) | |
258 | *ret_measured = true; | |
259 | ||
260 | return err; | |
261 | } | |
262 | ||
dede50a7 | 263 | EFI_STATUS tpm_log_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, size_t buffer_size, const char *description, bool *ret_measured) { |
8d5e4d59 LP |
264 | _cleanup_free_ char16_t *c = NULL; |
265 | ||
266 | if (description) | |
aee515bb | 267 | c = xstr8_to_16(description); |
8d5e4d59 LP |
268 | |
269 | return tpm_log_event(pcrindex, buffer, buffer_size, c, ret_measured); | |
92ed3bb4 HH |
270 | } |
271 | ||
8d5e4d59 | 272 | EFI_STATUS tpm_log_load_options(const char16_t *load_options, bool *ret_measured) { |
d84bdadb | 273 | bool measured = false; |
e6e24af5 LP |
274 | EFI_STATUS err; |
275 | ||
276 | /* Measures a load options string into the TPM2, i.e. the kernel command line */ | |
277 | ||
d84bdadb | 278 | err = tpm_log_event( |
2099cd62 | 279 | TPM2_PCR_KERNEL_CONFIG, |
d84bdadb JJ |
280 | POINTER_TO_PHYSICAL_ADDRESS(load_options), |
281 | strsize16(load_options), | |
282 | load_options, | |
283 | &measured); | |
284 | if (err != EFI_SUCCESS) | |
c2c62035 | 285 | return log_error_status( |
d84bdadb | 286 | err, |
2099cd62 LP |
287 | "Unable to add load options (i.e. kernel command) line measurement to PCR %i: %m", |
288 | TPM2_PCR_KERNEL_CONFIG); | |
e6e24af5 | 289 | |
8d5e4d59 | 290 | if (ret_measured) |
d84bdadb | 291 | *ret_measured = measured; |
8d5e4d59 | 292 | |
e6e24af5 LP |
293 | return EFI_SUCCESS; |
294 | } | |
295 | ||
92ed3bb4 | 296 | #endif |