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