]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/measure.c
shutdown: Make all mounts private
[thirdparty/systemd.git] / src / boot / efi / measure.c
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 "tpm-pcr.h"
9 #include "macro-fundamental.h"
10 #include "measure.h"
11 #include "missing_efi.h"
12 #include "util.h"
13
14 static EFI_STATUS tpm1_measure_to_pcr_and_event_log(
15 const EFI_TCG *tcg,
16 uint32_t pcrindex,
17 EFI_PHYSICAL_ADDRESS buffer,
18 UINTN buffer_size,
19 const char16_t *description) {
20
21 _cleanup_free_ TCG_PCR_EVENT *tcg_event = NULL;
22 EFI_PHYSICAL_ADDRESS event_log_last;
23 uint32_t event_number = 1;
24 UINTN desc_len;
25
26 assert(tcg);
27 assert(description);
28
29 desc_len = strsize16(description);
30 tcg_event = xmalloc(offsetof(TCG_PCR_EVENT, Event) + desc_len);
31 memset(tcg_event, 0, offsetof(TCG_PCR_EVENT, Event) + desc_len);
32 *tcg_event = (TCG_PCR_EVENT) {
33 .EventSize = desc_len,
34 .PCRIndex = pcrindex,
35 .EventType = EV_IPL,
36 };
37 memcpy(tcg_event->Event, description, desc_len);
38
39 return tcg->HashLogExtendEvent(
40 (EFI_TCG *) tcg,
41 buffer, buffer_size,
42 TCG_ALG_SHA,
43 tcg_event,
44 &event_number,
45 &event_log_last);
46 }
47
48 static EFI_STATUS tpm2_measure_to_pcr_and_event_log(
49 EFI_TCG2 *tcg,
50 uint32_t pcrindex,
51 EFI_PHYSICAL_ADDRESS buffer,
52 uint64_t buffer_size,
53 const char16_t *description) {
54
55 _cleanup_free_ EFI_TCG2_EVENT *tcg_event = NULL;
56 UINTN desc_len;
57
58 assert(tcg);
59 assert(description);
60
61 desc_len = strsize16(description);
62 tcg_event = xmalloc(offsetof(EFI_TCG2_EVENT, Event) + desc_len);
63 memset(tcg_event, 0, offsetof(EFI_TCG2_EVENT, Event) + desc_len);
64 *tcg_event = (EFI_TCG2_EVENT) {
65 .Size = offsetof(EFI_TCG2_EVENT, Event) + desc_len,
66 .Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER),
67 .Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION,
68 .Header.PCRIndex = pcrindex,
69 .Header.EventType = EV_IPL,
70 };
71
72 memcpy(tcg_event->Event, description, desc_len);
73
74 return tcg->HashLogExtendEvent(
75 tcg,
76 0,
77 buffer, buffer_size,
78 tcg_event);
79 }
80
81 static EFI_TCG *tcg1_interface_check(void) {
82 EFI_PHYSICAL_ADDRESS event_log_location, event_log_last_entry;
83 TCG_BOOT_SERVICE_CAPABILITY capability = {
84 .Size = sizeof(capability),
85 };
86 EFI_STATUS err;
87 uint32_t features;
88 EFI_TCG *tcg;
89
90 err = BS->LocateProtocol((EFI_GUID *) EFI_TCG_GUID, NULL, (void **) &tcg);
91 if (err != EFI_SUCCESS)
92 return NULL;
93
94 err = tcg->StatusCheck(
95 tcg,
96 &capability,
97 &features,
98 &event_log_location,
99 &event_log_last_entry);
100 if (err != EFI_SUCCESS)
101 return NULL;
102
103 if (capability.TPMDeactivatedFlag)
104 return NULL;
105
106 if (!capability.TPMPresentFlag)
107 return NULL;
108
109 return tcg;
110 }
111
112 static EFI_TCG2 * tcg2_interface_check(void) {
113 EFI_TCG2_BOOT_SERVICE_CAPABILITY capability = {
114 .Size = sizeof(capability),
115 };
116 EFI_STATUS err;
117 EFI_TCG2 *tcg;
118
119 err = BS->LocateProtocol((EFI_GUID *) EFI_TCG2_GUID, NULL, (void **) &tcg);
120 if (err != EFI_SUCCESS)
121 return NULL;
122
123 err = tcg->GetCapability(tcg, &capability);
124 if (err != EFI_SUCCESS)
125 return NULL;
126
127 if (capability.StructureVersion.Major == 1 &&
128 capability.StructureVersion.Minor == 0) {
129 TCG_BOOT_SERVICE_CAPABILITY *caps_1_0 =
130 (TCG_BOOT_SERVICE_CAPABILITY*) &capability;
131 if (caps_1_0->TPMPresentFlag)
132 return tcg;
133 }
134
135 if (!capability.TPMPresentFlag)
136 return NULL;
137
138 return tcg;
139 }
140
141 bool tpm_present(void) {
142 return tcg2_interface_check() || tcg1_interface_check();
143 }
144
145 EFI_STATUS tpm_log_event(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const char16_t *description, bool *ret_measured) {
146 EFI_TCG2 *tpm2;
147 EFI_STATUS err;
148
149 assert(description);
150
151 /* If EFI_SUCCESS is returned, will initialize ret_measured to true if we actually measured
152 * something, or false if measurement was turned off. */
153
154 if (pcrindex == UINT32_MAX) { /* PCR disabled? */
155 if (ret_measured)
156 *ret_measured = false;
157
158 return EFI_SUCCESS;
159 }
160
161 tpm2 = tcg2_interface_check();
162 if (tpm2)
163 err = tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
164 else {
165 EFI_TCG *tpm1;
166
167 tpm1 = tcg1_interface_check();
168 if (tpm1)
169 err = tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
170 else {
171 /* No active TPM found, so don't return an error */
172
173 if (ret_measured)
174 *ret_measured = false;
175
176 return EFI_SUCCESS;
177 }
178 }
179
180 if (err == EFI_SUCCESS && ret_measured)
181 *ret_measured = true;
182
183 return err;
184 }
185
186 EFI_STATUS tpm_log_event_ascii(uint32_t pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const char *description, bool *ret_measured) {
187 _cleanup_free_ char16_t *c = NULL;
188
189 if (description)
190 c = xstr8_to_16(description);
191
192 return tpm_log_event(pcrindex, buffer, buffer_size, c, ret_measured);
193 }
194
195 EFI_STATUS tpm_log_load_options(const char16_t *load_options, bool *ret_measured) {
196 bool measured = false;
197 EFI_STATUS err;
198
199 /* Measures a load options string into the TPM2, i.e. the kernel command line */
200
201 err = tpm_log_event(
202 TPM_PCR_INDEX_KERNEL_PARAMETERS,
203 POINTER_TO_PHYSICAL_ADDRESS(load_options),
204 strsize16(load_options),
205 load_options,
206 &measured);
207 if (err != EFI_SUCCESS)
208 return log_error_status_stall(
209 err,
210 L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r",
211 TPM_PCR_INDEX_KERNEL_PARAMETERS,
212 err);
213
214 if (ret_measured)
215 *ret_measured = measured;
216
217 return EFI_SUCCESS;
218 }
219
220 #endif