]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Measurement.c
0f1cb18bac95bf04c7944ee47e8f4f2d1b266405
[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 VariableData = NULL;
246 VariableDataSize = 0;
247 }
248
249 Status = MeasureVariable (
250 VariableName,
251 VendorGuid,
252 VariableData,
253 VariableDataSize
254 );
255 DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
256
257 if (VariableData != NULL) {
258 FreePool (VariableData);
259 }
260
261 //
262 // "SecureBoot" is 8bit & read-only. It can only be changed according to PK update
263 //
264 if ((StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0) &&
265 CompareGuid (VendorGuid, &gEfiGlobalVariableGuid)) {
266 Status = InternalGetVariable (
267 EFI_SECURE_BOOT_MODE_NAME,
268 &gEfiGlobalVariableGuid,
269 &VariableData,
270 &VariableDataSize
271 );
272 if (EFI_ERROR (Status)) {
273 return;
274 }
275
276 //
277 // If PK update is successful. "SecureBoot" shall always exist ever since variable write service is ready
278 //
279 ASSERT(mSecureBootVarData != NULL);
280
281 if (CompareMem(mSecureBootVarData, VariableData, VariableDataSize) != 0) {
282 FreePool(mSecureBootVarData);
283 mSecureBootVarData = VariableData;
284 mSecureBootVarDataSize = VariableDataSize;
285
286 DEBUG((DEBUG_INFO, "%s variable updated according to PK change. Remeasure the value!\n", EFI_SECURE_BOOT_MODE_NAME));
287 Status = MeasureVariable (
288 EFI_SECURE_BOOT_MODE_NAME,
289 &gEfiGlobalVariableGuid,
290 mSecureBootVarData,
291 mSecureBootVarDataSize
292 );
293 DEBUG ((DEBUG_INFO, "MeasureBootPolicyVariable - %r\n", Status));
294 } else {
295 //
296 // "SecureBoot" variable is not changed
297 //
298 FreePool(VariableData);
299 }
300 }
301
302 return ;
303 }
304
305 /**
306 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
307 Record their initial State when variable write service is ready.
308
309 **/
310 VOID
311 EFIAPI
312 RecordSecureBootPolicyVarData(
313 VOID
314 )
315 {
316 EFI_STATUS Status;
317
318 //
319 // Record initial "SecureBoot" variable value.
320 // It is used to detect SecureBoot variable change in SecureBootHook.
321 //
322 Status = InternalGetVariable (
323 EFI_SECURE_BOOT_MODE_NAME,
324 &gEfiGlobalVariableGuid,
325 (VOID **)&mSecureBootVarData,
326 &mSecureBootVarDataSize
327 );
328 if (EFI_ERROR(Status)) {
329 //
330 // Read could fail when Auth Variable solution is not supported
331 //
332 DEBUG((DEBUG_INFO, "RecordSecureBootPolicyVarData GetVariable %s Status %x\n", EFI_SECURE_BOOT_MODE_NAME, Status));
333 }
334 }