1 /** @file
2 Var Check PCD handler.
3
4 Copyright (c) 2015, 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 <Library/VarCheckLib.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/DxeServicesLib.h>
21
22 #include "VarCheckPcdStructure.h"
23
24 //#define DUMP_VAR_CHECK_PCD
25
26 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckPcdHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
27
28 /**
29 Dump some hexadecimal data.
30
31 @param[in] Indent How many spaces to indent the output.
32 @param[in] Offset The offset of the dump.
33 @param[in] DataSize The size in bytes of UserData.
34 @param[in] UserData The data to dump.
35
36 **/
37 VOID
VarCheckPcdInternalDumpHex(IN UINTN Indent,IN UINTN Offset,IN UINTN DataSize,IN VOID * UserData)38 VarCheckPcdInternalDumpHex (
39 IN UINTN Indent,
40 IN UINTN Offset,
41 IN UINTN DataSize,
42 IN VOID *UserData
43 )
44 {
45 UINT8 *Data;
46
47 CHAR8 Val[50];
48
49 CHAR8 Str[20];
50
51 UINT8 TempByte;
52 UINTN Size;
53 UINTN Index;
54
55 Data = UserData;
56 while (DataSize != 0) {
57 Size = 16;
58 if (Size > DataSize) {
59 Size = DataSize;
60 }
61
62 for (Index = 0; Index < Size; Index += 1) {
63 TempByte = Data[Index];
64 Val[Index * 3 + 0] = mVarCheckPcdHex[TempByte >> 4];
65 Val[Index * 3 + 1] = mVarCheckPcdHex[TempByte & 0xF];
66 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
67 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
68 }
69
70 Val[Index * 3] = 0;
71 Str[Index] = 0;
72 DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str));
73
74 Data += Size;
75 Offset += Size;
76 DataSize -= Size;
77 }
78 }
79
80 /**
81 Var Check Pcd ValidData.
82
83 @param[in] PcdValidData Pointer to Pcd ValidData
84 @param[in] Data Data pointer.
85 @param[in] DataSize Size of Data to set.
86
87 @retval TRUE Check pass
88 @retval FALSE Check fail.
89
90 **/
91 BOOLEAN
VarCheckPcdValidData(IN VAR_CHECK_PCD_VALID_DATA_HEADER * PcdValidData,IN VOID * Data,IN UINTN DataSize)92 VarCheckPcdValidData (
93 IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData,
94 IN VOID *Data,
95 IN UINTN DataSize
96 )
97 {
98 UINT64 OneData;
99 UINT64 Minimum;
100 UINT64 Maximum;
101 UINT64 OneValue;
102 UINT8 *Ptr;
103
104 OneData = 0;
105 CopyMem (&OneData, (UINT8 *) Data + PcdValidData->VarOffset, PcdValidData->StorageWidth);
106
107 switch (PcdValidData->Type) {
108 case VarCheckPcdValidList:
109 Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);
110 while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
111 OneValue = 0;
112 CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
113 if (OneData == OneValue) {
114 //
115 // Match
116 //
117 break;
118 }
119 Ptr += PcdValidData->StorageWidth;
120 }
121 if ((UINTN) Ptr >= ((UINTN) PcdValidData + PcdValidData->Length)) {
122 //
123 // No match
124 //
125 DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidList mismatch (0x%lx)\n", OneData));
126 DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););
127 return FALSE;
128 }
129 break;
130
131 case VarCheckPcdValidRange:
132 Minimum = 0;
133 Maximum = 0;
134 Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);
135 while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
136 CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
137 Ptr += PcdValidData->StorageWidth;
138 CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
139 Ptr += PcdValidData->StorageWidth;
140
141 if ((OneData >= Minimum) && (OneData <= Maximum)) {
142 return TRUE;
143 }
144 }
145 DEBUG ((EFI_D_INFO, "VarCheckPcdValidData fail: ValidRange mismatch (0x%lx)\n", OneData));
146 DEBUG_CODE (VarCheckPcdInternalDumpHex (2, 0, PcdValidData->Length, (UINT8 *) PcdValidData););
147 return FALSE;
148 break;
149
150 default:
151 ASSERT (FALSE);
152 break;
153 }
154
155 return TRUE;
156 }
157
158 VAR_CHECK_PCD_VARIABLE_HEADER *mVarCheckPcdBin = NULL;
159 UINTN mVarCheckPcdBinSize = 0;
160
161 /**
162 SetVariable check handler PCD.
163
164 @param[in] VariableName Name of Variable to set.
165 @param[in] VendorGuid Variable vendor GUID.
166 @param[in] Attributes Attribute value of the variable.
167 @param[in] DataSize Size of Data to set.
168 @param[in] Data Data pointer.
169
170 @retval EFI_SUCCESS The SetVariable check result was success.
171 @retval EFI_SECURITY_VIOLATION Check fail.
172
173 **/
174 EFI_STATUS
175 EFIAPI
SetVariableCheckHandlerPcd(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)176 SetVariableCheckHandlerPcd (
177 IN CHAR16 *VariableName,
178 IN EFI_GUID *VendorGuid,
179 IN UINT32 Attributes,
180 IN UINTN DataSize,
181 IN VOID *Data
182 )
183 {
184 VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
185 VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
186
187 if (mVarCheckPcdBin == NULL) {
188 return EFI_SUCCESS;
189 }
190
191 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
192 //
193 // Do not check delete variable.
194 //
195 return EFI_SUCCESS;
196 }
197
198 //
199 // For Pcd Variable header align.
200 //
201 PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckPcdBin);
202 while ((UINTN) PcdVariable < ((UINTN) mVarCheckPcdBin + mVarCheckPcdBinSize)) {
203 if ((StrCmp ((CHAR16 *) (PcdVariable + 1), VariableName) == 0) &&
204 (CompareGuid (&PcdVariable->Guid, VendorGuid))) {
205 //
206 // Found the Pcd Variable that could be used to do check.
207 //
208 DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize));
209 if ((PcdVariable->Attributes != 0) && PcdVariable->Attributes != Attributes) {
210 DEBUG ((EFI_D_INFO, "VarCheckPcdVariable fail for Attributes - 0x%08x\n", PcdVariable->Attributes));
211 return EFI_SECURITY_VIOLATION;
212 }
213
214 if (DataSize == 0) {
215 DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - CHECK PASS with DataSize == 0 !\n"));
216 return EFI_SUCCESS;
217 }
218
219 //
220 // Do the check.
221 // For Pcd ValidData header align.
222 //
223 PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));
224 while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {
225 if (((UINTN) PcdValidData->VarOffset + PcdValidData->StorageWidth) <= DataSize) {
226 if (!VarCheckPcdValidData (PcdValidData, Data, DataSize)) {
227 return EFI_SECURITY_VIOLATION;
228 }
229 }
230 //
231 // For Pcd ValidData header align.
232 //
233 PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));
234 }
235
236 DEBUG ((EFI_D_INFO, "VarCheckPcdVariable - ALL CHECK PASS!\n"));
237 return EFI_SUCCESS;
238 }
239 //
240 // For Pcd Variable header align.
241 //
242 PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));
243 }
244
245 // Not found, so pass.
246 return EFI_SUCCESS;
247 }
248
249 #ifdef DUMP_VAR_CHECK_PCD
250 /**
251 Dump Pcd ValidData.
252
253 @param[in] PcdValidData Pointer to Pcd ValidData.
254
255 **/
256 VOID
DumpPcdValidData(IN VAR_CHECK_PCD_VALID_DATA_HEADER * PcdValidData)257 DumpPcdValidData (
258 IN VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData
259 )
260 {
261 UINT64 Minimum;
262 UINT64 Maximum;
263 UINT64 OneValue;
264 UINT8 *Ptr;
265
266 DEBUG ((EFI_D_INFO, " VAR_CHECK_PCD_VALID_DATA_HEADER\n"));
267 DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdValidData->Type));
268 DEBUG ((EFI_D_INFO, " Length - 0x%02x\n", PcdValidData->Length));
269 DEBUG ((EFI_D_INFO, " VarOffset - 0x%04x\n", PcdValidData->VarOffset));
270 DEBUG ((EFI_D_INFO, " StorageWidth - 0x%02x\n", PcdValidData->StorageWidth));
271
272 switch (PcdValidData->Type) {
273 case VarCheckPcdValidList:
274 Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_LIST *) PcdValidData + 1);
275 while ((UINTN) Ptr < ((UINTN) PcdValidData + PcdValidData->Length)) {
276 OneValue = 0;
277 CopyMem (&OneValue, Ptr, PcdValidData->StorageWidth);
278 switch (PcdValidData->StorageWidth) {
279 case sizeof (UINT8):
280 DEBUG ((EFI_D_INFO, " ValidList - 0x%02x\n", OneValue));
281 break;
282 case sizeof (UINT16):
283 DEBUG ((EFI_D_INFO, " ValidList - 0x%04x\n", OneValue));
284 break;
285 case sizeof (UINT32):
286 DEBUG ((EFI_D_INFO, " ValidList - 0x%08x\n", OneValue));
287 break;
288 case sizeof (UINT64):
289 DEBUG ((EFI_D_INFO, " ValidList - 0x%016lx\n", OneValue));
290 break;
291 default:
292 ASSERT (FALSE);
293 break;
294 }
295 Ptr += PcdValidData->StorageWidth;
296 }
297 break;
298
299 case VarCheckPcdValidRange:
300 Minimum = 0;
301 Maximum = 0;
302 Ptr = (UINT8 *) ((VAR_CHECK_PCD_VALID_RANGE *) PcdValidData + 1);
303 while ((UINTN) Ptr < (UINTN) PcdValidData + PcdValidData->Length) {
304 CopyMem (&Minimum, Ptr, PcdValidData->StorageWidth);
305 Ptr += PcdValidData->StorageWidth;
306 CopyMem (&Maximum, Ptr, PcdValidData->StorageWidth);
307 Ptr += PcdValidData->StorageWidth;
308
309 switch (PcdValidData->StorageWidth) {
310 case sizeof (UINT8):
311 DEBUG ((EFI_D_INFO, " Minimum - 0x%02x\n", Minimum));
312 DEBUG ((EFI_D_INFO, " Maximum - 0x%02x\n", Maximum));
313 break;
314 case sizeof (UINT16):
315 DEBUG ((EFI_D_INFO, " Minimum - 0x%04x\n", Minimum));
316 DEBUG ((EFI_D_INFO, " Maximum - 0x%04x\n", Maximum));
317 break;
318 case sizeof (UINT32):
319 DEBUG ((EFI_D_INFO, " Minimum - 0x%08x\n", Minimum));
320 DEBUG ((EFI_D_INFO, " Maximum - 0x%08x\n", Maximum));
321 break;
322 case sizeof (UINT64):
323 DEBUG ((EFI_D_INFO, " Minimum - 0x%016lx\n", Minimum));
324 DEBUG ((EFI_D_INFO, " Maximum - 0x%016lx\n", Maximum));
325 break;
326 default:
327 ASSERT (FALSE);
328 break;
329 }
330 }
331 break;
332
333 default:
334 ASSERT (FALSE);
335 break;
336 }
337 }
338
339 /**
340 Dump Pcd Variable.
341
342 @param[in] PcdVariable Pointer to Pcd Variable.
343
344 **/
345 VOID
DumpPcdVariable(IN VAR_CHECK_PCD_VARIABLE_HEADER * PcdVariable)346 DumpPcdVariable (
347 IN VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable
348 )
349 {
350 VAR_CHECK_PCD_VALID_DATA_HEADER *PcdValidData;
351
352 DEBUG ((EFI_D_INFO, "VAR_CHECK_PCD_VARIABLE_HEADER\n"));
353 DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", PcdVariable->Revision));
354 DEBUG ((EFI_D_INFO, " HeaderLength - 0x%04x\n", PcdVariable->HeaderLength));
355 DEBUG ((EFI_D_INFO, " Length - 0x%08x\n", PcdVariable->Length));
356 DEBUG ((EFI_D_INFO, " Type - 0x%02x\n", PcdVariable->Type));
357 DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", PcdVariable->Attributes));
358 DEBUG ((EFI_D_INFO, " Guid - %g\n", &PcdVariable->Guid));
359 DEBUG ((EFI_D_INFO, " Name - %s\n", PcdVariable + 1));
360
361 //
362 // For Pcd ValidData header align.
363 //
364 PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->HeaderLength));
365 while ((UINTN) PcdValidData < ((UINTN) PcdVariable + PcdVariable->Length)) {
366 //
367 // Dump Pcd ValidData related to the Pcd Variable.
368 //
369 DumpPcdValidData (PcdValidData);
370 //
371 // For Pcd ValidData header align.
372 //
373 PcdValidData = (VAR_CHECK_PCD_VALID_DATA_HEADER *) HEADER_ALIGN (((UINTN) PcdValidData + PcdValidData->Length));
374 }
375 }
376
377 /**
378 Dump Var Check PCD.
379
380 @param[in] VarCheckPcdBin Pointer to VarCheckPcdBin.
381 @param[in] VarCheckPcdBinSize VarCheckPcdBin size.
382
383 **/
384 VOID
DumpVarCheckPcd(IN VOID * VarCheckPcdBin,IN UINTN VarCheckPcdBinSize)385 DumpVarCheckPcd (
386 IN VOID *VarCheckPcdBin,
387 IN UINTN VarCheckPcdBinSize
388 )
389 {
390 VAR_CHECK_PCD_VARIABLE_HEADER *PcdVariable;
391
392 DEBUG ((EFI_D_INFO, "DumpVarCheckPcd\n"));
393
394 //
395 // For Pcd Variable header align.
396 //
397 PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckPcdBin);
398 while ((UINTN) PcdVariable < ((UINTN) VarCheckPcdBin + VarCheckPcdBinSize)) {
399 DumpPcdVariable (PcdVariable);
400 //
401 // For Pcd Variable header align.
402 //
403 PcdVariable = (VAR_CHECK_PCD_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) PcdVariable + PcdVariable->Length));
404 }
405 }
406 #endif
407
408 /**
409 Locate VarCheckPcdBin.
410
411 **/
412 VOID
413 EFIAPI
LocateVarCheckPcdBin(VOID)414 LocateVarCheckPcdBin (
415 VOID
416 )
417 {
418 EFI_STATUS Status;
419 VAR_CHECK_PCD_VARIABLE_HEADER *VarCheckPcdBin;
420 UINTN VarCheckPcdBinSize;
421
422 //
423 // Search the VarCheckPcdBin from the first RAW section of current FFS.
424 //
425 Status = GetSectionFromFfs (
426 EFI_SECTION_RAW,
427 0,
428 (VOID **) &VarCheckPcdBin,
429 &VarCheckPcdBinSize
430 );
431 if (!EFI_ERROR (Status)) {
432 //
433 // AllocateRuntimeZeroPool () from MemoryAllocateLib is used for runtime access
434 // in SetVariable check handler.
435 //
436 mVarCheckPcdBin = AllocateRuntimeCopyPool (VarCheckPcdBinSize, VarCheckPcdBin);
437 ASSERT (mVarCheckPcdBin != NULL);
438 mVarCheckPcdBinSize = VarCheckPcdBinSize;
439 FreePool (VarCheckPcdBin);
440
441 DEBUG ((EFI_D_INFO, "VarCheckPcdBin - at 0x%x size = 0x%x\n", mVarCheckPcdBin, mVarCheckPcdBinSize));
442
443 #ifdef DUMP_VAR_CHECK_PCD
444 DEBUG_CODE (
445 DumpVarCheckPcd (mVarCheckPcdBin, mVarCheckPcdBinSize);
446 );
447 #endif
448 } else {
449 DEBUG ((EFI_D_INFO, "[VarCheckPcd] No VarCheckPcdBin found at the first RAW section\n"));
450 }
451 }
452
453 /**
454 Constructor function of VarCheckPcdLib to register var check PCD handler.
455
456 @param[in] ImageHandle The firmware allocated handle for the EFI image.
457 @param[in] SystemTable A pointer to the EFI System Table.
458
459 @retval EFI_SUCCESS The constructor executed correctly.
460
461 **/
462 EFI_STATUS
463 EFIAPI
VarCheckPcdLibNullClassConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)464 VarCheckPcdLibNullClassConstructor (
465 IN EFI_HANDLE ImageHandle,
466 IN EFI_SYSTEM_TABLE *SystemTable
467 )
468 {
469 LocateVarCheckPcdBin ();
470 VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckPcdBin);
471 VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerPcd);
472
473 return EFI_SUCCESS;
474 }
475