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