1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "macro-fundamental.h"
7 #include "memory-util-fundamental.h"
8 #include "proto/cc-measurement.h"
13 static EFI_STATUS
tpm2_measure_to_pcr_and_tagged_event_log(
14 EFI_TCG2_PROTOCOL
*tcg
,
16 EFI_PHYSICAL_ADDRESS buffer
,
19 const char16_t
*description
) {
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
;
30 desc_len
= strsize16(description
);
31 event_size
= offsetof(EFI_TCG2_EVENT
, Event
) + offsetof(EFI_TCG2_TAGGED_EVENT
, Event
) + desc_len
;
33 event
= xmalloc(event_size
);
34 *event
= (struct event
) {
35 .tcg_event
= (EFI_TCG2_EVENT
) {
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
,
44 .EventSize
= desc_len
,
47 memcpy(event
->tcg_tagged_event
.Event
, description
, desc_len
);
49 return tcg
->HashLogExtendEvent(
56 static EFI_STATUS
tpm2_measure_to_pcr_and_event_log(
57 EFI_TCG2_PROTOCOL
*tcg
,
59 EFI_PHYSICAL_ADDRESS buffer
,
61 const char16_t
*description
) {
63 _cleanup_free_ EFI_TCG2_EVENT
*tcg_event
= NULL
;
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
75 desc_len
= strsize16(description
);
76 tcg_event
= xmalloc(offsetof(EFI_TCG2_EVENT
, Event
) + desc_len
);
77 *tcg_event
= (EFI_TCG2_EVENT
) {
78 .Size
= offsetof(EFI_TCG2_EVENT
, Event
) + desc_len
,
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
,
85 memcpy(tcg_event
->Event
, description
, desc_len
);
87 return tcg
->HashLogExtendEvent(
94 static EFI_STATUS
cc_measure_to_mr_and_event_log(
95 EFI_CC_MEASUREMENT_PROTOCOL
*cc
,
97 EFI_PHYSICAL_ADDRESS buffer
,
99 const char16_t
*description
) {
101 _cleanup_free_ EFI_CC_EVENT
*event
= NULL
;
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
;
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
,
126 memcpy(event
->Event
, description
, desc_len
);
128 return cc
->HashLogExtendEvent(
136 static EFI_CC_MEASUREMENT_PROTOCOL
*cc_interface_check(void) {
137 EFI_CC_BOOT_SERVICE_CAPABILITY capability
= {
138 .Size
= sizeof(capability
),
141 EFI_CC_MEASUREMENT_PROTOCOL
*cc
;
143 err
= BS
->LocateProtocol(MAKE_GUID_PTR(EFI_CC_MEASUREMENT_PROTOCOL
), NULL
, (void **) &cc
);
144 if (err
!= EFI_SUCCESS
)
147 err
= cc
->GetCapability(cc
, &capability
);
148 if (err
!= EFI_SUCCESS
)
151 if (!(capability
.SupportedEventLogs
& EFI_CC_EVENT_LOG_FORMAT_TCG_2
))
157 static EFI_TCG2_PROTOCOL
*tcg2_interface_check(void) {
158 EFI_TCG2_BOOT_SERVICE_CAPABILITY capability
= {
159 .Size
= sizeof(capability
),
162 EFI_TCG2_PROTOCOL
*tcg
;
164 err
= BS
->LocateProtocol(MAKE_GUID_PTR(EFI_TCG2_PROTOCOL
), NULL
, (void **) &tcg
);
165 if (err
!= EFI_SUCCESS
)
168 err
= tcg
->GetCapability(tcg
, &capability
);
169 if (err
!= EFI_SUCCESS
)
172 if (capability
.StructureVersion
.Major
== 1 &&
173 capability
.StructureVersion
.Minor
== 0) {
174 EFI_TCG_BOOT_SERVICE_CAPABILITY
*caps_1_0
=
175 (EFI_TCG_BOOT_SERVICE_CAPABILITY
*) &capability
;
176 if (caps_1_0
->TPMPresentFlag
)
180 if (!capability
.TPMPresentFlag
)
186 bool tpm_present(void) {
187 return tcg2_interface_check();
190 static EFI_STATUS
tcg2_log_event(uint32_t pcrindex
, EFI_PHYSICAL_ADDRESS buffer
, size_t buffer_size
, const char16_t
*description
, bool *ret_measured
) {
191 EFI_TCG2_PROTOCOL
*tpm2
;
192 EFI_STATUS err
= EFI_SUCCESS
;
194 assert(ret_measured
);
196 tpm2
= tcg2_interface_check();
198 err
= tpm2_measure_to_pcr_and_event_log(tpm2
, pcrindex
, buffer
, buffer_size
, description
);
200 *ret_measured
= tpm2
&& (err
== EFI_SUCCESS
);
205 static EFI_STATUS
cc_log_event(uint32_t pcrindex
, EFI_PHYSICAL_ADDRESS buffer
, size_t buffer_size
, const char16_t
*description
, bool *ret_measured
) {
206 EFI_CC_MEASUREMENT_PROTOCOL
*cc
;
207 EFI_STATUS err
= EFI_SUCCESS
;
209 assert(ret_measured
);
211 cc
= cc_interface_check();
213 err
= cc_measure_to_mr_and_event_log(cc
, pcrindex
, buffer
, buffer_size
, description
);
215 *ret_measured
= cc
&& (err
== EFI_SUCCESS
);
220 EFI_STATUS
tpm_log_event(uint32_t pcrindex
, EFI_PHYSICAL_ADDRESS buffer
, size_t buffer_size
, const char16_t
*description
, bool *ret_measured
) {
222 bool tpm_ret_measured
, cc_ret_measured
;
224 assert(description
|| pcrindex
== UINT32_MAX
);
226 /* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured
227 * something, or false if measurement was turned off. */
229 if (pcrindex
== UINT32_MAX
) { /* PCR disabled? */
231 *ret_measured
= false;
236 /* Measure into both CC and TPM if both are available to avoid a problem like CVE-2021-42299 */
237 err
= cc_log_event(pcrindex
, buffer
, buffer_size
, description
, &cc_ret_measured
);
238 if (err
!= EFI_SUCCESS
)
241 err
= tcg2_log_event(pcrindex
, buffer
, buffer_size
, description
, &tpm_ret_measured
);
243 if (err
== EFI_SUCCESS
&& ret_measured
)
244 *ret_measured
= tpm_ret_measured
|| cc_ret_measured
;
249 EFI_STATUS
tpm_log_tagged_event(
251 EFI_PHYSICAL_ADDRESS buffer
,
254 const char16_t
*description
,
255 bool *ret_measured
) {
257 EFI_TCG2_PROTOCOL
*tpm2
;
260 assert(description
|| pcrindex
== UINT32_MAX
);
261 assert(event_id
> 0);
263 /* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured
264 * something, or false if measurement was turned off. */
266 tpm2
= tcg2_interface_check();
267 if (!tpm2
|| pcrindex
== UINT32_MAX
) { /* PCR disabled? */
269 *ret_measured
= false;
274 err
= tpm2_measure_to_pcr_and_tagged_event_log(tpm2
, pcrindex
, buffer
, buffer_size
, event_id
, description
);
275 if (err
== EFI_SUCCESS
&& ret_measured
)
276 *ret_measured
= true;
281 EFI_STATUS
tpm_log_event_ascii(uint32_t pcrindex
, EFI_PHYSICAL_ADDRESS buffer
, size_t buffer_size
, const char *description
, bool *ret_measured
) {
282 _cleanup_free_ char16_t
*c
= NULL
;
285 c
= xstr8_to_16(description
);
287 return tpm_log_event(pcrindex
, buffer
, buffer_size
, c
, ret_measured
);
290 EFI_STATUS
tpm_log_load_options(const char16_t
*load_options
, bool *ret_measured
) {
291 bool measured
= false;
294 /* Measures a load options string into the TPM2, i.e. the kernel command line */
297 TPM2_PCR_KERNEL_CONFIG
,
298 POINTER_TO_PHYSICAL_ADDRESS(load_options
),
299 strsize16(load_options
),
302 if (err
!= EFI_SUCCESS
)
303 return log_error_status(
305 "Unable to add load options (i.e. kernel command) line measurement to PCR %i: %m",
306 TPM2_PCR_KERNEL_CONFIG
);
309 *ret_measured
= measured
;