1 /** @file
2   Implementation functions and structures for var check services.
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/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 
21 #include <Guid/GlobalVariable.h>
22 #include <Guid/HardwareErrorVariable.h>
23 
24 BOOLEAN mVarCheckLibEndOfDxe    = FALSE;
25 
26 #define VAR_CHECK_TABLE_SIZE    0x8
27 
28 UINTN                                   mVarCheckLibEndOfDxeCallbackCount = 0;
29 UINTN                                   mVarCheckLibEndOfDxeCallbackMaxCount = 0;
30 VAR_CHECK_END_OF_DXE_CALLBACK           *mVarCheckLibEndOfDxeCallback = NULL;
31 
32 UINTN                                   mVarCheckLibAddressPointerCount = 0;
33 UINTN                                   mVarCheckLibAddressPointerMaxCount = 0;
34 VOID                                    ***mVarCheckLibAddressPointer = NULL;
35 
36 UINTN                                   mNumberOfVarCheckHandler = 0;
37 UINTN                                   mMaxNumberOfVarCheckHandler = 0;
38 VAR_CHECK_SET_VARIABLE_CHECK_HANDLER    *mVarCheckHandlerTable = NULL;
39 
40 typedef struct {
41   EFI_GUID                      Guid;
42   VAR_CHECK_VARIABLE_PROPERTY   VariableProperty;
43   //CHAR16                        *Name;
44 } VAR_CHECK_VARIABLE_ENTRY;
45 
46 UINTN                                   mNumberOfVarCheckVariable = 0;
47 UINTN                                   mMaxNumberOfVarCheckVariable = 0;
48 VARIABLE_ENTRY_PROPERTY                 **mVarCheckVariableTable = NULL;
49 
50 //
51 // Handle variables with wildcard name specially.
52 //
53 VARIABLE_ENTRY_PROPERTY mVarCheckVariableWithWildcardName[] = {
54   {
55     &gEfiGlobalVariableGuid,
56     L"Boot####",
57     {
58       0
59     },
60   },
61   {
62     &gEfiGlobalVariableGuid,
63     L"Driver####",
64     {
65       0
66     },
67   },
68   {
69     &gEfiGlobalVariableGuid,
70     L"SysPrep####",
71     {
72       0
73     },
74   },
75   {
76     &gEfiGlobalVariableGuid,
77     L"Key####",
78     {
79       0
80     },
81   },
82   {
83     &gEfiGlobalVariableGuid,
84     L"PlatformRecovery####",
85     {
86       0
87     },
88   },
89   {
90     &gEfiHardwareErrorVariableGuid,
91     L"HwErrRec####",
92     {
93       0
94     },
95   },
96 };
97 
98 /**
99   Check if a Unicode character is a hexadecimal character.
100 
101   This function checks if a Unicode character is a
102   hexadecimal character.  The valid hexadecimal character is
103   L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
104 
105 
106   @param[in] Char       The character to check against.
107 
108   @retval TRUE          If the Char is a hexadecmial character.
109   @retval FALSE         If the Char is not a hexadecmial character.
110 
111 **/
112 BOOLEAN
113 EFIAPI
VarCheckInternalIsHexaDecimalDigitCharacter(IN CHAR16 Char)114 VarCheckInternalIsHexaDecimalDigitCharacter (
115   IN CHAR16             Char
116   )
117 {
118   return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
119 }
120 
121 /**
122   Variable property get with wildcard name.
123 
124   @param[in] VariableName       Pointer to variable name.
125   @param[in] VendorGuid         Pointer to variable vendor GUID.
126   @param[in] WildcardMatch      Try wildcard match or not.
127 
128   @return Pointer to variable property.
129 
130 **/
131 VAR_CHECK_VARIABLE_PROPERTY *
VariablePropertyGetWithWildcardName(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN BOOLEAN WildcardMatch)132 VariablePropertyGetWithWildcardName (
133   IN CHAR16                         *VariableName,
134   IN EFI_GUID                       *VendorGuid,
135   IN BOOLEAN                        WildcardMatch
136   )
137 {
138   UINTN     Index;
139   UINTN     NameLength;
140 
141   NameLength = StrLen (VariableName) - 4;
142   for (Index = 0; Index < sizeof (mVarCheckVariableWithWildcardName)/sizeof (mVarCheckVariableWithWildcardName[0]); Index++) {
143     if (CompareGuid (mVarCheckVariableWithWildcardName[Index].Guid, VendorGuid)){
144       if (WildcardMatch) {
145         if ((StrLen (VariableName) == StrLen (mVarCheckVariableWithWildcardName[Index].Name)) &&
146             (StrnCmp (VariableName, mVarCheckVariableWithWildcardName[Index].Name, NameLength) == 0) &&
147             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength]) &&
148             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 1]) &&
149             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 2]) &&
150             VarCheckInternalIsHexaDecimalDigitCharacter (VariableName[NameLength + 3])) {
151           return &mVarCheckVariableWithWildcardName[Index].VariableProperty;
152         }
153       }
154       if (StrCmp (mVarCheckVariableWithWildcardName[Index].Name, VariableName) == 0) {
155         return  &mVarCheckVariableWithWildcardName[Index].VariableProperty;
156       }
157     }
158   }
159 
160   return NULL;
161 }
162 
163 /**
164   Variable property get function.
165 
166   @param[in] Name           Pointer to the variable name.
167   @param[in] Guid           Pointer to the vendor GUID.
168   @param[in] WildcardMatch  Try wildcard match or not.
169 
170   @return Pointer to the property of variable specified by the Name and Guid.
171 
172 **/
173 VAR_CHECK_VARIABLE_PROPERTY *
VariablePropertyGetFunction(IN CHAR16 * Name,IN EFI_GUID * Guid,IN BOOLEAN WildcardMatch)174 VariablePropertyGetFunction (
175   IN CHAR16                 *Name,
176   IN EFI_GUID               *Guid,
177   IN BOOLEAN                WildcardMatch
178   )
179 {
180   UINTN                     Index;
181   VAR_CHECK_VARIABLE_ENTRY  *Entry;
182   CHAR16                    *VariableName;
183 
184   for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
185     Entry = (VAR_CHECK_VARIABLE_ENTRY *) mVarCheckVariableTable[Index];
186     VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
187     if (CompareGuid (&Entry->Guid, Guid) && (StrCmp (VariableName, Name) == 0)) {
188       return &Entry->VariableProperty;
189     }
190   }
191 
192   return VariablePropertyGetWithWildcardName (Name, Guid, WildcardMatch);
193 }
194 
195 /**
196   Var check add table entry.
197 
198   @param[in, out] Table         Pointer to table buffer.
199   @param[in, out] MaxNumber     Pointer to maximum number of entry in the table.
200   @param[in, out] CurrentNumber Pointer to current number of entry in the table.
201   @param[in]      Entry         Entry will be added to the table.
202 
203   @retval EFI_SUCCESS           Reallocate memory successfully.
204   @retval EFI_OUT_OF_RESOURCES  No enough memory to allocate.
205 
206 **/
207 EFI_STATUS
VarCheckAddTableEntry(IN OUT UINTN ** Table,IN OUT UINTN * MaxNumber,IN OUT UINTN * CurrentNumber,IN UINTN Entry)208 VarCheckAddTableEntry (
209   IN OUT UINTN      **Table,
210   IN OUT UINTN      *MaxNumber,
211   IN OUT UINTN      *CurrentNumber,
212   IN UINTN          Entry
213   )
214 {
215   UINTN     *TempTable;
216 
217   //
218   // Check whether the table is enough to store new entry.
219   //
220   if (*CurrentNumber == *MaxNumber) {
221     //
222     // Reallocate memory for the table.
223     //
224     TempTable = ReallocateRuntimePool (
225                   *MaxNumber * sizeof (UINTN),
226                   (*MaxNumber + VAR_CHECK_TABLE_SIZE) * sizeof (UINTN),
227                   *Table
228                   );
229 
230     //
231     // No enough resource to allocate.
232     //
233     if (TempTable == NULL) {
234       return EFI_OUT_OF_RESOURCES;
235     }
236 
237     *Table = TempTable;
238     //
239     // Increase max number.
240     //
241     *MaxNumber += VAR_CHECK_TABLE_SIZE;
242   }
243 
244   //
245   // Add entry to the table.
246   //
247   (*Table)[*CurrentNumber] = Entry;
248   (*CurrentNumber)++;
249 
250   return EFI_SUCCESS;
251 }
252 
253 /**
254   Register END_OF_DXE callback.
255   The callback will be invoked by VarCheckLibInitializeAtEndOfDxe().
256 
257   @param[in] Callback           END_OF_DXE callback.
258 
259   @retval EFI_SUCCESS           The callback was registered successfully.
260   @retval EFI_INVALID_PARAMETER Callback is NULL.
261   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
262                                 already been signaled.
263   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the callback register request.
264 
265 **/
266 EFI_STATUS
267 EFIAPI
VarCheckLibRegisterEndOfDxeCallback(IN VAR_CHECK_END_OF_DXE_CALLBACK Callback)268 VarCheckLibRegisterEndOfDxeCallback (
269   IN VAR_CHECK_END_OF_DXE_CALLBACK  Callback
270   )
271 {
272   EFI_STATUS    Status;
273 
274   if (Callback == NULL) {
275     return EFI_INVALID_PARAMETER;
276   }
277 
278   if (mVarCheckLibEndOfDxe) {
279     return EFI_ACCESS_DENIED;
280   }
281 
282   Status = VarCheckAddTableEntry (
283            (UINTN **) &mVarCheckLibEndOfDxeCallback,
284            &mVarCheckLibEndOfDxeCallbackMaxCount,
285            &mVarCheckLibEndOfDxeCallbackCount,
286            (UINTN) Callback
287            );
288 
289   DEBUG ((EFI_D_INFO, "VarCheckLibRegisterEndOfDxeCallback - 0x%x %r\n", Callback, Status));
290 
291   return Status;
292 }
293 
294 /**
295   Var check initialize at END_OF_DXE.
296 
297   This function needs to be called at END_OF_DXE.
298   Address pointers may be returned,
299   and caller needs to ConvertPointer() for the pointers.
300 
301   @param[in, out] AddressPointerCount   Output pointer to address pointer count.
302 
303   @return Address pointer buffer, NULL if input AddressPointerCount is NULL.
304 
305 **/
306 VOID ***
307 EFIAPI
VarCheckLibInitializeAtEndOfDxe(IN OUT UINTN * AddressPointerCount OPTIONAL)308 VarCheckLibInitializeAtEndOfDxe (
309   IN OUT UINTN                  *AddressPointerCount OPTIONAL
310   )
311 {
312   VOID                          *TempTable;
313   UINTN                         TotalCount;
314   UINTN                         Index;
315 
316   for (Index = 0; Index < mVarCheckLibEndOfDxeCallbackCount; Index++) {
317     //
318     // Invoke the callback registered by VarCheckLibRegisterEndOfDxeCallback().
319     //
320     mVarCheckLibEndOfDxeCallback[Index] ();
321   }
322   if (mVarCheckLibEndOfDxeCallback != NULL) {
323     //
324     // Free the callback buffer.
325     //
326     mVarCheckLibEndOfDxeCallbackCount = 0;
327     mVarCheckLibEndOfDxeCallbackMaxCount = 0;
328     FreePool ((VOID *) mVarCheckLibEndOfDxeCallback);
329     mVarCheckLibEndOfDxeCallback = NULL;
330   }
331 
332   mVarCheckLibEndOfDxe = TRUE;
333 
334   if (AddressPointerCount == NULL) {
335     if (mVarCheckLibAddressPointer != NULL) {
336       //
337       // Free the address pointer buffer.
338       //
339       mVarCheckLibAddressPointerCount = 0;
340       mVarCheckLibAddressPointerMaxCount = 0;
341       FreePool ((VOID *) mVarCheckLibAddressPointer);
342       mVarCheckLibAddressPointer = NULL;
343     }
344     return NULL;
345   }
346 
347   //
348   // Get the total count needed.
349   // Also cover VarCheckHandler and the entries, and VarCheckVariable and the entries.
350   //
351   TotalCount = mVarCheckLibAddressPointerCount + (mNumberOfVarCheckHandler + 1) + (mNumberOfVarCheckVariable + 1);
352   TempTable = ReallocateRuntimePool (
353                 mVarCheckLibAddressPointerMaxCount * sizeof (VOID **),
354                 TotalCount * sizeof (VOID **),
355                 (VOID *) mVarCheckLibAddressPointer
356                 );
357 
358   if (TempTable != NULL) {
359     mVarCheckLibAddressPointer = (VOID ***) TempTable;
360 
361     //
362     // Cover VarCheckHandler and the entries.
363     //
364     mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable;
365     for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
366       mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckHandlerTable[Index];
367     }
368 
369     //
370     // Cover VarCheckVariable and the entries.
371     //
372     mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable;
373     for (Index = 0; Index < mNumberOfVarCheckVariable; Index++) {
374       mVarCheckLibAddressPointer[mVarCheckLibAddressPointerCount++] = (VOID **) &mVarCheckVariableTable[Index];
375     }
376 
377     ASSERT (mVarCheckLibAddressPointerCount == TotalCount);
378     mVarCheckLibAddressPointerMaxCount = mVarCheckLibAddressPointerCount;
379   }
380 
381   *AddressPointerCount = mVarCheckLibAddressPointerCount;
382   return mVarCheckLibAddressPointer;
383 }
384 
385 /**
386   Register address pointer.
387   The AddressPointer may be returned by VarCheckLibInitializeAtEndOfDxe().
388 
389   @param[in] AddressPointer     Address pointer.
390 
391   @retval EFI_SUCCESS           The address pointer was registered successfully.
392   @retval EFI_INVALID_PARAMETER AddressPointer is NULL.
393   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
394                                 already been signaled.
395   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the address pointer register request.
396 
397 **/
398 EFI_STATUS
399 EFIAPI
VarCheckLibRegisterAddressPointer(IN VOID ** AddressPointer)400 VarCheckLibRegisterAddressPointer (
401   IN VOID                       **AddressPointer
402   )
403 {
404   EFI_STATUS    Status;
405 
406   if (AddressPointer == NULL) {
407     return EFI_INVALID_PARAMETER;
408   }
409 
410   if (mVarCheckLibEndOfDxe) {
411     return EFI_ACCESS_DENIED;
412   }
413 
414   Status = VarCheckAddTableEntry(
415            (UINTN **) &mVarCheckLibAddressPointer,
416            &mVarCheckLibAddressPointerMaxCount,
417            &mVarCheckLibAddressPointerCount,
418            (UINTN) AddressPointer
419            );
420 
421   DEBUG ((EFI_D_INFO, "VarCheckLibRegisterAddressPointer - 0x%x %r\n", AddressPointer, Status));
422 
423   return Status;
424 }
425 
426 /**
427   Register SetVariable check handler.
428 
429   @param[in] Handler            Pointer to check handler.
430 
431   @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
432   @retval EFI_INVALID_PARAMETER Handler is NULL.
433   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
434                                 already been signaled.
435   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
436   @retval EFI_UNSUPPORTED       This interface is not implemented.
437                                 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
438 
439 **/
440 EFI_STATUS
441 EFIAPI
VarCheckLibRegisterSetVariableCheckHandler(IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler)442 VarCheckLibRegisterSetVariableCheckHandler (
443   IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler
444   )
445 {
446   EFI_STATUS    Status;
447 
448   if (Handler == NULL) {
449     return EFI_INVALID_PARAMETER;
450   }
451 
452   if (mVarCheckLibEndOfDxe) {
453     return EFI_ACCESS_DENIED;
454   }
455 
456   Status =  VarCheckAddTableEntry(
457              (UINTN **) &mVarCheckHandlerTable,
458              &mMaxNumberOfVarCheckHandler,
459              &mNumberOfVarCheckHandler,
460              (UINTN) Handler
461              );
462 
463   DEBUG ((EFI_D_INFO, "VarCheckLibRegisterSetVariableCheckHandler - 0x%x %r\n", Handler, Status));
464 
465   return Status;
466 }
467 
468 /**
469   Variable property set.
470 
471   @param[in] Name               Pointer to the variable name.
472   @param[in] Guid               Pointer to the vendor GUID.
473   @param[in] VariableProperty   Pointer to the input variable property.
474 
475   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
476   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
477                                 or the fields of VariableProperty are not valid.
478   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
479                                 already been signaled.
480   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
481 
482 **/
483 EFI_STATUS
484 EFIAPI
VarCheckLibVariablePropertySet(IN CHAR16 * Name,IN EFI_GUID * Guid,IN VAR_CHECK_VARIABLE_PROPERTY * VariableProperty)485 VarCheckLibVariablePropertySet (
486   IN CHAR16                         *Name,
487   IN EFI_GUID                       *Guid,
488   IN VAR_CHECK_VARIABLE_PROPERTY    *VariableProperty
489   )
490 {
491   EFI_STATUS                    Status;
492   VAR_CHECK_VARIABLE_ENTRY      *Entry;
493   CHAR16                        *VariableName;
494   VAR_CHECK_VARIABLE_PROPERTY   *Property;
495 
496   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
497     return EFI_INVALID_PARAMETER;
498   }
499 
500   if (VariableProperty == NULL) {
501     return EFI_INVALID_PARAMETER;
502   }
503 
504   if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
505     return EFI_INVALID_PARAMETER;
506   }
507 
508   if (mVarCheckLibEndOfDxe) {
509     return EFI_ACCESS_DENIED;
510   }
511 
512   Status = EFI_SUCCESS;
513 
514   //
515   // Get the pointer of property data for set.
516   //
517   Property = VariablePropertyGetFunction (Name, Guid, FALSE);
518   if (Property != NULL) {
519     CopyMem (Property, VariableProperty, sizeof (*VariableProperty));
520   } else {
521     Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (Name));
522     if (Entry == NULL) {
523       return EFI_OUT_OF_RESOURCES;
524     }
525     VariableName = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));
526     StrCpyS (VariableName, StrSize (Name)/sizeof (CHAR16), Name);
527     CopyGuid (&Entry->Guid, Guid);
528     CopyMem (&Entry->VariableProperty, VariableProperty, sizeof (*VariableProperty));
529 
530     Status = VarCheckAddTableEntry(
531                (UINTN **) &mVarCheckVariableTable,
532                &mMaxNumberOfVarCheckVariable,
533                &mNumberOfVarCheckVariable,
534                (UINTN) Entry
535                );
536 
537     if (EFI_ERROR (Status)) {
538       FreePool (Entry);
539     }
540   }
541 
542   return Status;
543 }
544 
545 /**
546   Variable property get.
547 
548   @param[in]  Name              Pointer to the variable name.
549   @param[in]  Guid              Pointer to the vendor GUID.
550   @param[out] VariableProperty  Pointer to the output variable property.
551 
552   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
553   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
554   @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
555 
556 **/
557 EFI_STATUS
558 EFIAPI
VarCheckLibVariablePropertyGet(IN CHAR16 * Name,IN EFI_GUID * Guid,OUT VAR_CHECK_VARIABLE_PROPERTY * VariableProperty)559 VarCheckLibVariablePropertyGet (
560   IN CHAR16                         *Name,
561   IN EFI_GUID                       *Guid,
562   OUT VAR_CHECK_VARIABLE_PROPERTY   *VariableProperty
563   )
564 {
565   VAR_CHECK_VARIABLE_PROPERTY   *Property;
566 
567   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
568     return EFI_INVALID_PARAMETER;
569   }
570 
571   if (VariableProperty == NULL) {
572     return EFI_INVALID_PARAMETER;
573   }
574 
575   Property = VariablePropertyGetFunction (Name, Guid, TRUE);
576   //
577   // Also check the property revision before using the property data.
578   // There is no property set to this variable(wildcard name)
579   // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
580   //
581   if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
582     CopyMem (VariableProperty, Property, sizeof (*VariableProperty));
583     return EFI_SUCCESS;
584   }
585 
586   return EFI_NOT_FOUND;
587 }
588 
589 /**
590   SetVariable check.
591 
592   @param[in] VariableName       Name of Variable to set.
593   @param[in] VendorGuid         Variable vendor GUID.
594   @param[in] Attributes         Attribute value of the variable.
595   @param[in] DataSize           Size of Data to set.
596   @param[in] Data               Data pointer.
597   @param[in] RequestSource      Request source.
598 
599   @retval EFI_SUCCESS           The SetVariable check result was success.
600   @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, GUID,
601                                 DataSize and Data value was supplied.
602   @retval EFI_WRITE_PROTECTED   The variable in question is read-only.
603   @retval Others                The other return status from check handler.
604 
605 **/
606 EFI_STATUS
607 EFIAPI
VarCheckLibSetVariableCheck(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data,IN VAR_CHECK_REQUEST_SOURCE RequestSource)608 VarCheckLibSetVariableCheck (
609   IN CHAR16                     *VariableName,
610   IN EFI_GUID                   *VendorGuid,
611   IN UINT32                     Attributes,
612   IN UINTN                      DataSize,
613   IN VOID                       *Data,
614   IN VAR_CHECK_REQUEST_SOURCE   RequestSource
615   )
616 {
617   EFI_STATUS                    Status;
618   UINTN                         Index;
619   VAR_CHECK_VARIABLE_PROPERTY   *Property;
620 
621   if (!mVarCheckLibEndOfDxe) {
622     //
623     // Only do check after End Of Dxe.
624     //
625     return EFI_SUCCESS;
626   }
627 
628   Property = VariablePropertyGetFunction (VariableName, VendorGuid, TRUE);
629   //
630   // Also check the property revision before using the property data.
631   // There is no property set to this variable(wildcard name)
632   // if the revision is not VAR_CHECK_VARIABLE_PROPERTY_REVISION.
633   //
634   if ((Property != NULL) && (Property->Revision == VAR_CHECK_VARIABLE_PROPERTY_REVISION)) {
635     if ((RequestSource != VarCheckFromTrusted) && ((Property->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0)) {
636       DEBUG ((EFI_D_INFO, "Variable Check ReadOnly variable fail %r - %g:%s\n", EFI_WRITE_PROTECTED, VendorGuid, VariableName));
637       return EFI_WRITE_PROTECTED;
638     }
639     if (!((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0))) {
640       //
641       // Not to delete variable.
642       //
643       if ((Property->Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Property->Attributes)) {
644         DEBUG ((EFI_D_INFO, "Variable Check Attributes(0x%08x to 0x%08x) fail %r - %g:%s\n", Property->Attributes, Attributes, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
645         return EFI_INVALID_PARAMETER;
646       }
647       if (DataSize != 0) {
648         if ((DataSize < Property->MinSize) || (DataSize > Property->MaxSize)) {
649           DEBUG ((EFI_D_INFO, "Variable Check DataSize fail(0x%x not in 0x%x - 0x%x) %r - %g:%s\n", DataSize, Property->MinSize, Property->MaxSize, EFI_INVALID_PARAMETER, VendorGuid, VariableName));
650           return EFI_INVALID_PARAMETER;
651         }
652       }
653     }
654   }
655 
656   for (Index = 0; Index < mNumberOfVarCheckHandler; Index++) {
657     Status = mVarCheckHandlerTable[Index] (
658                VariableName,
659                VendorGuid,
660                Attributes,
661                DataSize,
662                Data
663                );
664     if (EFI_ERROR (Status)) {
665       DEBUG ((EFI_D_INFO, "Variable Check handler fail %r - %g:%s\n", Status, VendorGuid, VariableName));
666       return Status;
667     }
668   }
669   return EFI_SUCCESS;
670 }
671