Home | History | Annotate | Download | only in VarCheckPcdLib
      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
     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
     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
    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
    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
    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
    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
    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
    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