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