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