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