]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c
MdeModulePkg: Variable: Update PCR[7] measure for new TCG spec
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Measurement.c
1 /** @file
2 Measure TrEE required variable.
3
4 Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <PiDxe.h>
16 #include <Guid/ImageAuthentication.h>
17 #include <IndustryStandard/UefiTcgPlatform.h>
18 #include <Protocol/TrEEProtocol.h>
19
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/TpmMeasurementLib.h>
27
28 typedef struct {
29 CHAR16 *VariableName;
30 EFI_GUID *VendorGuid;
31 } VARIABLE_TYPE;
32
33 VARIABLE_TYPE mVariableType[] = {
34 {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid},
35 {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid},
36 {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid},
37 {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid},
38 {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
39 {EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid},
40 };
41
42 //
43 // "SecureBoot" may update following PK Del/Add
44 // Cache its value to detect value update
45 //
46 UINT8 *mSecureBootVarData = NULL;
47 UINTN mSecureBootVarDataSize = 0;
48
49 /**
50 This function will return if this variable is SecureBootPolicy Variable.
51
52 @param[in] VariableName A Null-terminated string that is the name of the vendor's variable.
53 @param[in] VendorGuid A unique identifier for the vendor.
54
55 @retval TRUE This is SecureBootPolicy Variable
56 @retval FALSE This is not SecureBootPolicy Variable
57 **/
58 BOOLEAN
59 IsSecureBootPolicyVariable (
60 IN CHAR16 *VariableName,
61 IN EFI_GUID *VendorGuid
62 )
63 {
64 UINTN Index;
65
66 for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
67 if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
68 (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
69 return TRUE;
70 }
71 }
72 return FALSE;
73 }
74
75 /**
76 Measure and log an EFI variable, and extend the measurement result into a specific PCR.
77
78 @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
79 @param[in] VendorGuid A unique identifier for the vendor.
80 @param[in] VarData The content of the variable data.
81 @param[in] VarSize The size of the variable data.
82
83 @retval EFI_SUCCESS Operation completed successfully.
84 @retval EFI_OUT_OF_RESOURCES Out of memory.
85 @retval EFI_DEVICE_ERROR The operation was unsuccessful.
86
87 **/
88 EFI_STATUS
89 EFIAPI
90 MeasureVariable (
91 IN CHAR16 *VarName,
92 IN EFI_GUID *VendorGuid,
93 IN VOID *VarData,
94 IN UINTN VarSize
95 )
96 {
97 EFI_STATUS Status;
98 UINTN VarNameLength;
99 EFI_VARIABLE_DATA_TREE *VarLog;
100 UINT32 VarLogSize;
101
102 ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL));
103
104 VarNameLength = StrLen (VarName);
105 VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
106 - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
107
108 VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
109 if (VarLog == NULL) {
110 return EFI_OUT_OF_RESOURCES;
111 }
112
113 CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName));
114 VarLog->UnicodeNameLength = VarNameLength;
115 VarLog->VariableDataLength = VarSize;
116 CopyMem (
117 VarLog->UnicodeName,
118 VarName,
119 VarNameLength * sizeof (*VarName)
120 );
121 if (VarSize != 0) {
122 CopyMem (
123 (CHAR16 *)VarLog->UnicodeName + VarNameLength,
124 VarData,
125 VarSize
126 );
127 }
128
129 DEBUG ((EFI_D_INFO, "AuthVariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY));
130 DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
131
132 Status = TpmMeasureAndLogData (
133 7,
134 EV_EFI_VARIABLE_DRIVER_CONFIG,
135 VarLog,
136 VarLogSize,
137 VarLog,
138 VarLogSize
139 );
140 FreePool (VarLog);
141 return Status;
142 }
143
144 /**
145 Returns the status whether get the variable success. The function retrieves
146 variable through the UEFI Runtime Service GetVariable(). The
147 returned buffer is allocated using AllocatePool(). The caller is responsible
148 for freeing this buffer with FreePool().
149
150 This API is only invoked in boot time. It may NOT be invoked at runtime.
151
152 @param[in] Name The pointer to a Null-terminated Unicode string.
153 @param[in] Guid The pointer to an EFI_GUID structure
154 @param[out] Value The buffer point saved the variable info.
155 @param[out] Size The buffer size of the variable.
156
157 @return EFI_OUT_OF_RESOURCES Allocate buffer failed.
158 @return EFI_SUCCESS Find the specified variable.
159 @return Others Errors Return errors from call to gRT->GetVariable.
160
161 **/
162 EFI_STATUS
163 InternalGetVariable (
164 IN CONST CHAR16 *Name,
165 IN CONST EFI_GUID *Guid,
166 OUT VOID **Value,
167 OUT UINTN *Size
168 )
169 {
170 EFI_STATUS Status;
171 UINTN BufferSize;
172
173 //
174 // Try to get the variable size.
175 //
176 BufferSize = 0;
177 *Value = NULL;
178 if (Size != NULL) {
179 *Size = 0;
180 }
181
182 Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
183 if (Status != EFI_BUFFER_TOO_SMALL) {
184 return Status;
185 }
186
187 //
188 // Allocate buffer to get the variable.
189 //
190 *Value = AllocatePool (BufferSize);
191 ASSERT (*Value != NULL);
192 if (*Value == NULL) {
193 return EFI_OUT_OF_RESOURCES;
194 }
195
196 //
197 // Get the variable data.
198 //
199 Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
200 if (EFI_ERROR (Status)) {
201 FreePool(*Value);
202 *Value = NULL;
203 }
204
205 if (Size != NULL) {
206 *Size = BufferSize;
207 }
208
209 return Status;
210 }
211
212 /**
213 SecureBoot Hook for SetVariable.
214
215 @param[in] VariableName Name of Variable to be found.
216 @param[in] VendorGuid Variable vendor GUID.
217
218 **/
219 VOID
220 EFIAPI
221 SecureBootHook (
222 IN CHAR16 *VariableName,
223 IN EFI_GUID *VendorGuid
224 )
225 {
226 EFI_STATUS Status;
227 UINTN VariableDataSize;
228 VOID *VariableData;
229
230 if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) {
231 return ;
232 }
233
234 //
235 // We should NOT use Data and DataSize here,because it may include signature,
236 // or is just partial with append attributes, or is deleted.
237 // We should GetVariable again, to get full variable content.
238 //
239 Status = InternalGetVariable (
240 VariableName,
241 VendorGuid,
242 &VariableData,
243 &VariableDataSize
244 );
245 if (EFI_ERROR (Status)) {
246 VariableData = NULL;
247 VariableDataSize = 0;
248 }
249
250 Status = MeasureVariable (
251 VariableName,
252 VendorGuid,
253 VariableData,
254 VariableDataSize
255 );
256 DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
257
258 if (VariableData != NULL) {
259 FreePool (VariableData);
260 }
261
262 //
263 // "SecureBoot" is 8bit & read-only. It can only be changed according to PK update
264 //
265 if ((StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0) &&
266 CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
267 Status = InternalGetVariable (
268 EFI_SECURE_BOOT_MODE_NAME,
269 &gEfiGlobalVariableGuid,
270 &VariableData,
271 &VariableDataSize
272 );
273 if (EFI_ERROR (Status)) {
274 return;
275 }
276
277 //
278 // If PK update is successful. "SecureBoot" shall always exist ever since variable write service is ready
279 //
280 ASSERT(mSecureBootVarData != NULL);
281
282 if (CompareMem(mSecureBootVarData, VariableData, VariableDataSize) != 0) {
283 FreePool(mSecureBootVarData);
284 mSecureBootVarData = VariableData;
285 mSecureBootVarDataSize = VariableDataSize;
286
287 DEBUG((DEBUG_INFO, "%s variable updated according to PK change. Remeasure the value!\n", EFI_SECURE_BOOT_MODE_NAME));
288 Status = MeasureVariable (
289 EFI_SECURE_BOOT_MODE_NAME,
290 &gEfiGlobalVariableGuid,
291 mSecureBootVarData,
292 mSecureBootVarDataSize
293 );
294 DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status));
295 } else {
296 //
297 // "SecureBoot" variable is not changed
298 //
299 FreePool(VariableData);
300 }
301 }
302
303 return ;
304 }
305
306 /**
307 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
308 Record their initial State when variable write service is ready.
309
310 **/
311 VOID
312 EFIAPI
313 RecordSecureBootPolicyVarData(
314 VOID
315 )
316 {
317 EFI_STATUS Status;
318
319 //
320 // Record initial "SecureBoot" variable value.
321 // It is used to detect SecureBoot variable change in SecureBootHook.
322 //
323 Status = InternalGetVariable (
324 EFI_SECURE_BOOT_MODE_NAME,
325 &gEfiGlobalVariableGuid,
326 (VOID **)&mSecureBootVarData,
327 &mSecureBootVarDataSize
328 );
329 if (EFI_ERROR(Status)) {
330 //
331 // Read could fail when Auth Variable solution is not supported
332 //
333 DEBUG((DEBUG_INFO, "RecordSecureBootPolicyVarData GetVariable %s Status %x\n", EFI_SECURE_BOOT_MODE_NAME, Status));
334 }
335 }