1 /** @file
2   Measure TrEE required variable.
3 
4 Copyright (c) 2013 - 2014, 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 #include <Protocol/TrEEProtocol.h>
19 
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/BaseLib.h>
26 #include <Library/TpmMeasurementLib.h>
27 
28 typedef struct {
29   CHAR16                                 *VariableName;
30   EFI_GUID                               *VendorGuid;
31 } VARIABLE_TYPE;
32 
33 VARIABLE_TYPE  mVariableType[] = {
34   {EFI_SECURE_BOOT_MODE_NAME,    &gEfiGlobalVariableGuid},
35   {EFI_PLATFORM_KEY_NAME,        &gEfiGlobalVariableGuid},
36   {EFI_KEY_EXCHANGE_KEY_NAME,    &gEfiGlobalVariableGuid},
37   {EFI_IMAGE_SECURITY_DATABASE,  &gEfiImageSecurityDatabaseGuid},
38   {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
39 };
40 
41 /**
42   This function will return if this variable is SecureBootPolicy Variable.
43 
44   @param[in]  VariableName      A Null-terminated string that is the name of the vendor's variable.
45   @param[in]  VendorGuid        A unique identifier for the vendor.
46 
47   @retval TRUE  This is SecureBootPolicy Variable
48   @retval FALSE This is not SecureBootPolicy Variable
49 **/
50 BOOLEAN
IsSecureBootPolicyVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid)51 IsSecureBootPolicyVariable (
52   IN CHAR16                                 *VariableName,
53   IN EFI_GUID                               *VendorGuid
54   )
55 {
56   UINTN   Index;
57 
58   for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
59     if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
60         (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
61       return TRUE;
62     }
63   }
64   return FALSE;
65 }
66 
67 /**
68   Measure and log an EFI variable, and extend the measurement result into a specific PCR.
69 
70   @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.
71   @param[in]  VendorGuid        A unique identifier for the vendor.
72   @param[in]  VarData           The content of the variable data.
73   @param[in]  VarSize           The size of the variable data.
74 
75   @retval EFI_SUCCESS           Operation completed successfully.
76   @retval EFI_OUT_OF_RESOURCES  Out of memory.
77   @retval EFI_DEVICE_ERROR      The operation was unsuccessful.
78 
79 **/
80 EFI_STATUS
81 EFIAPI
MeasureVariable(IN CHAR16 * VarName,IN EFI_GUID * VendorGuid,IN VOID * VarData,IN UINTN VarSize)82 MeasureVariable (
83   IN      CHAR16                    *VarName,
84   IN      EFI_GUID                  *VendorGuid,
85   IN      VOID                      *VarData,
86   IN      UINTN                     VarSize
87   )
88 {
89   EFI_STATUS                        Status;
90   UINTN                             VarNameLength;
91   EFI_VARIABLE_DATA_TREE            *VarLog;
92   UINT32                            VarLogSize;
93 
94   ASSERT ((VarSize == 0 && VarData == NULL) || (VarSize != 0 && VarData != NULL));
95 
96   VarNameLength      = StrLen (VarName);
97   VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
98                         - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
99 
100   VarLog = (EFI_VARIABLE_DATA_TREE *) AllocateZeroPool (VarLogSize);
101   if (VarLog == NULL) {
102     return EFI_OUT_OF_RESOURCES;
103   }
104 
105   CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName));
106   VarLog->UnicodeNameLength  = VarNameLength;
107   VarLog->VariableDataLength = VarSize;
108   CopyMem (
109      VarLog->UnicodeName,
110      VarName,
111      VarNameLength * sizeof (*VarName)
112      );
113   if (VarSize != 0) {
114     CopyMem (
115        (CHAR16 *)VarLog->UnicodeName + VarNameLength,
116        VarData,
117        VarSize
118        );
119   }
120 
121   DEBUG ((EFI_D_INFO, "AuthVariableDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY));
122   DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
123 
124   Status = TpmMeasureAndLogData (
125              7,
126              EV_EFI_VARIABLE_DRIVER_CONFIG,
127              VarLog,
128              VarLogSize,
129              VarLog,
130              VarLogSize
131              );
132   FreePool (VarLog);
133   return Status;
134 }
135 
136 /**
137   Returns the status whether get the variable success. The function retrieves
138   variable  through the UEFI Runtime Service GetVariable().  The
139   returned buffer is allocated using AllocatePool().  The caller is responsible
140   for freeing this buffer with FreePool().
141 
142   This API is only invoked in boot time. It may NOT be invoked at runtime.
143 
144   @param[in]  Name  The pointer to a Null-terminated Unicode string.
145   @param[in]  Guid  The pointer to an EFI_GUID structure
146   @param[out] Value The buffer point saved the variable info.
147   @param[out] Size  The buffer size of the variable.
148 
149   @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
150   @return EFI_SUCCESS               Find the specified variable.
151   @return Others Errors             Return errors from call to gRT->GetVariable.
152 
153 **/
154 EFI_STATUS
InternalGetVariable(IN CONST CHAR16 * Name,IN CONST EFI_GUID * Guid,OUT VOID ** Value,OUT UINTN * Size)155 InternalGetVariable (
156   IN CONST CHAR16    *Name,
157   IN CONST EFI_GUID  *Guid,
158   OUT VOID           **Value,
159   OUT UINTN          *Size
160   )
161 {
162   EFI_STATUS  Status;
163   UINTN       BufferSize;
164 
165   //
166   // Try to get the variable size.
167   //
168   BufferSize = 0;
169   *Value     = NULL;
170   if (Size != NULL) {
171     *Size  = 0;
172   }
173 
174   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
175   if (Status != EFI_BUFFER_TOO_SMALL) {
176     return Status;
177   }
178 
179   //
180   // Allocate buffer to get the variable.
181   //
182   *Value = AllocatePool (BufferSize);
183   ASSERT (*Value != NULL);
184   if (*Value == NULL) {
185     return EFI_OUT_OF_RESOURCES;
186   }
187 
188   //
189   // Get the variable data.
190   //
191   Status = gRT->GetVariable ((CHAR16 *) Name, (EFI_GUID *) Guid, NULL, &BufferSize, *Value);
192   if (EFI_ERROR (Status)) {
193     FreePool(*Value);
194     *Value = NULL;
195   }
196 
197   if (Size != NULL) {
198     *Size = BufferSize;
199   }
200 
201   return Status;
202 }
203 
204 /**
205   SecureBoot Hook for SetVariable.
206 
207   @param[in] VariableName                 Name of Variable to be found.
208   @param[in] VendorGuid                   Variable vendor GUID.
209 
210 **/
211 VOID
212 EFIAPI
SecureBootHook(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid)213 SecureBootHook (
214   IN CHAR16                                 *VariableName,
215   IN EFI_GUID                               *VendorGuid
216   )
217 {
218   EFI_STATUS                        Status;
219   UINTN                             VariableDataSize;
220   VOID                              *VariableData;
221 
222   if (!IsSecureBootPolicyVariable (VariableName, VendorGuid)) {
223     return ;
224   }
225 
226   //
227   // We should NOT use Data and DataSize here,because it may include signature,
228   // or is just partial with append attributes, or is deleted.
229   // We should GetVariable again, to get full variable content.
230   //
231   Status = InternalGetVariable (
232              VariableName,
233              VendorGuid,
234              &VariableData,
235              &VariableDataSize
236              );
237   if (EFI_ERROR (Status)) {
238     VariableData     = NULL;
239     VariableDataSize = 0;
240   }
241 
242   Status = MeasureVariable (
243              VariableName,
244              VendorGuid,
245              VariableData,
246              VariableDataSize
247              );
248   DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
249 
250   if (VariableData != NULL) {
251     FreePool (VariableData);
252   }
253 
254   return ;
255 }
256