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