]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/boot/efi/measure.c
Merge pull request #31000 from flatcar-hub/krnowak/mutable-overlays
[thirdparty/systemd.git] / src / boot / efi / measure.c
CommitLineData
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
13static 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 56static 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
94static 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
136static 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 157static 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 186bool tpm_present(void) {
13fc754d 187 return tcg2_interface_check();
a87e9cd7
JJ
188}
189
dede50a7 190EFI_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
231EFI_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 263EFI_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 272EFI_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