1 /** @file 2 Var Check Hii 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 "VarCheckHii.h" 16 17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mVarCheckHiiHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; 18 19 /** 20 Dump some hexadecimal data. 21 22 @param[in] Indent How many spaces to indent the output. 23 @param[in] Offset The offset of the dump. 24 @param[in] DataSize The size in bytes of UserData. 25 @param[in] UserData The data to dump. 26 27 **/ 28 VOID 29 VarCheckHiiInternalDumpHex ( 30 IN UINTN Indent, 31 IN UINTN Offset, 32 IN UINTN DataSize, 33 IN VOID *UserData 34 ) 35 { 36 UINT8 *Data; 37 38 CHAR8 Val[50]; 39 40 CHAR8 Str[20]; 41 42 UINT8 TempByte; 43 UINTN Size; 44 UINTN Index; 45 46 Data = UserData; 47 while (DataSize != 0) { 48 Size = 16; 49 if (Size > DataSize) { 50 Size = DataSize; 51 } 52 53 for (Index = 0; Index < Size; Index += 1) { 54 TempByte = Data[Index]; 55 Val[Index * 3 + 0] = mVarCheckHiiHex[TempByte >> 4]; 56 Val[Index * 3 + 1] = mVarCheckHiiHex[TempByte & 0xF]; 57 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' '); 58 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte); 59 } 60 61 Val[Index * 3] = 0; 62 Str[Index] = 0; 63 DEBUG ((EFI_D_INFO, "%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str)); 64 65 Data += Size; 66 Offset += Size; 67 DataSize -= Size; 68 } 69 } 70 71 /** 72 Var Check Hii Question. 73 74 @param[in] HiiQuestion Pointer to Hii Question 75 @param[in] Data Data pointer. 76 @param[in] DataSize Size of Data to set. 77 78 @retval TRUE Check pass 79 @retval FALSE Check fail. 80 81 **/ 82 BOOLEAN 83 VarCheckHiiQuestion ( 84 IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion, 85 IN VOID *Data, 86 IN UINTN DataSize 87 ) 88 { 89 UINT64 OneData; 90 UINT64 Minimum; 91 UINT64 Maximum; 92 UINT64 OneValue; 93 UINT8 *Ptr; 94 UINT8 Index; 95 UINT8 MaxContainers; 96 97 if ((UINTN) (HiiQuestion->VarOffset + HiiQuestion->StorageWidth) > DataSize) { 98 DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, DataSize)); 99 return FALSE; 100 } 101 102 OneData = 0; 103 CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset, HiiQuestion->StorageWidth); 104 105 switch (HiiQuestion->OpCode) { 106 case EFI_IFR_ONE_OF_OP: 107 Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1); 108 while ((UINTN) Ptr < (UINTN) HiiQuestion + HiiQuestion->Length) { 109 OneValue = 0; 110 CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth); 111 if (OneData == OneValue) { 112 // 113 // Match 114 // 115 break; 116 } 117 Ptr += HiiQuestion->StorageWidth; 118 } 119 if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) { 120 // 121 // No match 122 // 123 DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: OneOf mismatch (0x%lx)\n", OneData)); 124 DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion);); 125 return FALSE; 126 } 127 break; 128 129 case EFI_IFR_CHECKBOX_OP: 130 if ((OneData != 0) && (OneData != 1)) { 131 DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: CheckBox mismatch (0x%lx)\n", OneData)); 132 DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion);); 133 return FALSE; 134 } 135 break; 136 137 case EFI_IFR_NUMERIC_OP: 138 Minimum = 0; 139 Maximum = 0; 140 Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1); 141 CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth); 142 Ptr += HiiQuestion->StorageWidth; 143 CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth); 144 Ptr += HiiQuestion->StorageWidth; 145 146 // 147 // No need to check Step, because it is ONLY for UI. 148 // 149 if ((OneData < Minimum) || (OneData > Maximum)) { 150 DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: Numeric mismatch (0x%lx)\n", OneData)); 151 DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion);); 152 return FALSE; 153 } 154 break; 155 156 case EFI_IFR_ORDERED_LIST_OP: 157 MaxContainers = ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers; 158 if ((UINTN) (HiiQuestion->VarOffset + HiiQuestion->StorageWidth * MaxContainers) > DataSize) { 159 DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: (VarOffset(0x%04x) + StorageWidth(0x%02x) * MaxContainers(0x%02x)) > Size(0x%x)\n", HiiQuestion->VarOffset, HiiQuestion->StorageWidth, MaxContainers, DataSize)); 160 return FALSE; 161 } 162 for (Index = 0; Index < MaxContainers; Index++) { 163 OneData = 0; 164 CopyMem (&OneData, (UINT8 *) Data + HiiQuestion->VarOffset + HiiQuestion->StorageWidth * Index, HiiQuestion->StorageWidth); 165 if (OneData == 0) { 166 // 167 // The value of 0 is used to determine if a particular "slot" in the array is empty. 168 // 169 continue; 170 } 171 172 Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1); 173 while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) { 174 OneValue = 0; 175 CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth); 176 if (OneData == OneValue) { 177 // 178 // Match 179 // 180 break; 181 } 182 Ptr += HiiQuestion->StorageWidth; 183 } 184 if ((UINTN) Ptr >= ((UINTN) HiiQuestion + HiiQuestion->Length)) { 185 // 186 // No match 187 // 188 DEBUG ((EFI_D_INFO, "VarCheckHiiQuestion fail: OrderedList mismatch\n")); 189 DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->StorageWidth * MaxContainers, (UINT8 *) Data + HiiQuestion->VarOffset);); 190 DEBUG_CODE (VarCheckHiiInternalDumpHex (2, 0, HiiQuestion->Length, (UINT8 *) HiiQuestion);); 191 return FALSE; 192 } 193 } 194 break; 195 196 default: 197 ASSERT (FALSE); 198 break; 199 } 200 201 return TRUE; 202 } 203 204 VAR_CHECK_HII_VARIABLE_HEADER *mVarCheckHiiBin = NULL; 205 UINTN mVarCheckHiiBinSize = 0; 206 207 /** 208 SetVariable check handler HII. 209 210 @param[in] VariableName Name of Variable to set. 211 @param[in] VendorGuid Variable vendor GUID. 212 @param[in] Attributes Attribute value of the variable. 213 @param[in] DataSize Size of Data to set. 214 @param[in] Data Data pointer. 215 216 @retval EFI_SUCCESS The SetVariable check result was success. 217 @retval EFI_SECURITY_VIOLATION Check fail. 218 219 **/ 220 EFI_STATUS 221 EFIAPI 222 SetVariableCheckHandlerHii ( 223 IN CHAR16 *VariableName, 224 IN EFI_GUID *VendorGuid, 225 IN UINT32 Attributes, 226 IN UINTN DataSize, 227 IN VOID *Data 228 ) 229 { 230 VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable; 231 VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion; 232 233 if (mVarCheckHiiBin == NULL) { 234 return EFI_SUCCESS; 235 } 236 237 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) { 238 // 239 // Do not check delete variable. 240 // 241 return EFI_SUCCESS; 242 } 243 244 // 245 // For Hii Variable header align. 246 // 247 HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (mVarCheckHiiBin); 248 while ((UINTN) HiiVariable < ((UINTN) mVarCheckHiiBin + mVarCheckHiiBinSize)) { 249 if ((StrCmp ((CHAR16 *) (HiiVariable + 1), VariableName) == 0) && 250 (CompareGuid (&HiiVariable->Guid, VendorGuid))) { 251 // 252 // Found the Hii Variable that could be used to do check. 253 // 254 DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - %s:%g with Attributes = 0x%08x Size = 0x%x\n", VariableName, VendorGuid, Attributes, DataSize)); 255 if (HiiVariable->Attributes != Attributes) { 256 DEBUG ((EFI_D_INFO, "VarCheckHiiVariable fail for Attributes - 0x%08x\n", HiiVariable->Attributes)); 257 return EFI_SECURITY_VIOLATION; 258 } 259 260 if (DataSize == 0) { 261 DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - CHECK PASS with DataSize == 0 !\n")); 262 return EFI_SUCCESS; 263 } 264 265 if (HiiVariable->Size != DataSize) { 266 DEBUG ((EFI_D_INFO, "VarCheckHiiVariable fail for Size - 0x%x\n", HiiVariable->Size)); 267 return EFI_SECURITY_VIOLATION; 268 } 269 270 // 271 // Do the check. 272 // For Hii Question header align. 273 // 274 HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->HeaderLength)); 275 while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) { 276 if (!VarCheckHiiQuestion (HiiQuestion, Data, DataSize)) { 277 return EFI_SECURITY_VIOLATION; 278 } 279 // 280 // For Hii Question header align. 281 // 282 HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiQuestion + HiiQuestion->Length)); 283 } 284 285 DEBUG ((EFI_D_INFO, "VarCheckHiiVariable - ALL CHECK PASS!\n")); 286 return EFI_SUCCESS; 287 } 288 // 289 // For Hii Variable header align. 290 // 291 HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->Length)); 292 } 293 294 // Not found, so pass. 295 return EFI_SUCCESS; 296 } 297 298 #ifdef DUMP_VAR_CHECK_HII 299 GLOBAL_REMOVE_IF_UNREFERENCED VAR_CHECK_HII_OPCODE_STRING mHiiOpCodeStringTable[] = { 300 {EFI_IFR_VARSTORE_EFI_OP, "EfiVarStore"}, 301 {EFI_IFR_ONE_OF_OP, "OneOf"}, 302 {EFI_IFR_CHECKBOX_OP, "CheckBox"}, 303 {EFI_IFR_NUMERIC_OP, "Numeric"}, 304 {EFI_IFR_ORDERED_LIST_OP, "OrderedList"}, 305 }; 306 307 /** 308 HII opcode to string. 309 310 @param[in] HiiOpCode Hii OpCode. 311 312 @return Pointer to string. 313 314 **/ 315 CHAR8 * 316 HiiOpCodeToStr ( 317 IN UINT8 HiiOpCode 318 ) 319 { 320 UINTN Index; 321 for (Index = 0; Index < sizeof (mHiiOpCodeStringTable) / sizeof (mHiiOpCodeStringTable[0]); Index++) { 322 if (mHiiOpCodeStringTable[Index].HiiOpCode == HiiOpCode) { 323 return mHiiOpCodeStringTable[Index].HiiOpCodeStr; 324 } 325 } 326 327 return "<UnknownHiiOpCode>"; 328 } 329 330 /** 331 Dump Hii Question. 332 333 @param[in] HiiQuestion Pointer to Hii Question. 334 335 **/ 336 VOID 337 DumpHiiQuestion ( 338 IN VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion 339 ) 340 { 341 UINT64 Minimum; 342 UINT64 Maximum; 343 UINT64 OneValue; 344 UINT8 *Ptr; 345 346 DEBUG ((EFI_D_INFO, " VAR_CHECK_HII_QUESTION_HEADER\n")); 347 DEBUG ((EFI_D_INFO, " OpCode - 0x%02x (%a)\n", HiiQuestion->OpCode, HiiOpCodeToStr (HiiQuestion->OpCode))); 348 DEBUG ((EFI_D_INFO, " Length - 0x%02x\n", HiiQuestion->Length)); 349 DEBUG ((EFI_D_INFO, " VarOffset - 0x%04x\n", HiiQuestion->VarOffset)); 350 DEBUG ((EFI_D_INFO, " StorageWidth - 0x%02x\n", HiiQuestion->StorageWidth)); 351 352 switch (HiiQuestion->OpCode) { 353 case EFI_IFR_ONE_OF_OP: 354 Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ONEOF *) HiiQuestion + 1); 355 while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) { 356 OneValue = 0; 357 CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth); 358 switch (HiiQuestion->StorageWidth) { 359 case sizeof (UINT8): 360 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%02x\n", OneValue)); 361 break; 362 case sizeof (UINT16): 363 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%04x\n", OneValue)); 364 break; 365 case sizeof (UINT32): 366 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%08x\n", OneValue)); 367 break; 368 case sizeof (UINT64): 369 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%016lx\n", OneValue)); 370 break; 371 default: 372 ASSERT (FALSE); 373 break; 374 } 375 Ptr += HiiQuestion->StorageWidth; 376 } 377 break; 378 379 case EFI_IFR_CHECKBOX_OP: 380 break; 381 382 case EFI_IFR_NUMERIC_OP: 383 Minimum = 0; 384 Maximum = 0; 385 Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_NUMERIC *) HiiQuestion + 1); 386 CopyMem (&Minimum, Ptr, HiiQuestion->StorageWidth); 387 Ptr += HiiQuestion->StorageWidth; 388 CopyMem (&Maximum, Ptr, HiiQuestion->StorageWidth); 389 Ptr += HiiQuestion->StorageWidth; 390 391 switch (HiiQuestion->StorageWidth) { 392 case sizeof (UINT8): 393 DEBUG ((EFI_D_INFO, " Minimum - 0x%02x\n", Minimum)); 394 DEBUG ((EFI_D_INFO, " Maximum - 0x%02x\n", Maximum)); 395 break; 396 case sizeof (UINT16): 397 DEBUG ((EFI_D_INFO, " Minimum - 0x%04x\n", Minimum)); 398 DEBUG ((EFI_D_INFO, " Maximum - 0x%04x\n", Maximum)); 399 break; 400 case sizeof (UINT32): 401 DEBUG ((EFI_D_INFO, " Minimum - 0x%08x\n", Minimum)); 402 DEBUG ((EFI_D_INFO, " Maximum - 0x%08x\n", Maximum)); 403 break; 404 case sizeof (UINT64): 405 DEBUG ((EFI_D_INFO, " Minimum - 0x%016lx\n", Minimum)); 406 DEBUG ((EFI_D_INFO, " Maximum - 0x%016lx\n", Maximum)); 407 break; 408 default: 409 ASSERT (FALSE); 410 break; 411 } 412 break; 413 414 case EFI_IFR_ORDERED_LIST_OP: 415 DEBUG ((EFI_D_INFO, " MaxContainers - 0x%02x\n", ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion)->MaxContainers)); 416 Ptr = (UINT8 *) ((VAR_CHECK_HII_QUESTION_ORDEREDLIST *) HiiQuestion + 1); 417 while ((UINTN) Ptr < ((UINTN) HiiQuestion + HiiQuestion->Length)) { 418 OneValue = 0; 419 CopyMem (&OneValue, Ptr, HiiQuestion->StorageWidth); 420 switch (HiiQuestion->StorageWidth) { 421 case sizeof (UINT8): 422 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%02x\n", OneValue)); 423 break; 424 case sizeof (UINT16): 425 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%04x\n", OneValue)); 426 break; 427 case sizeof (UINT32): 428 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%08x\n", OneValue)); 429 break; 430 case sizeof (UINT64): 431 DEBUG ((EFI_D_INFO, " OneOfOption - 0x%016lx\n", OneValue)); 432 break; 433 default: 434 ASSERT (FALSE); 435 break; 436 } 437 Ptr += HiiQuestion->StorageWidth; 438 } 439 break; 440 441 default: 442 ASSERT (FALSE); 443 break; 444 } 445 } 446 447 /** 448 Dump Hii Variable. 449 450 @param[in] HiiVariable Pointer to Hii Variable. 451 452 **/ 453 VOID 454 DumpHiiVariable ( 455 IN VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable 456 ) 457 { 458 VAR_CHECK_HII_QUESTION_HEADER *HiiQuestion; 459 460 DEBUG ((EFI_D_INFO, "VAR_CHECK_HII_VARIABLE_HEADER\n")); 461 DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", HiiVariable->Revision)); 462 DEBUG ((EFI_D_INFO, " HeaderLength - 0x%04x\n", HiiVariable->HeaderLength)); 463 DEBUG ((EFI_D_INFO, " Length - 0x%08x\n", HiiVariable->Length)); 464 DEBUG ((EFI_D_INFO, " OpCode - 0x%02x (%a)\n", HiiVariable->OpCode, HiiOpCodeToStr (HiiVariable->OpCode))); 465 DEBUG ((EFI_D_INFO, " Size - 0x%04x\n", HiiVariable->Size)); 466 DEBUG ((EFI_D_INFO, " Attributes - 0x%08x\n", HiiVariable->Attributes)); 467 DEBUG ((EFI_D_INFO, " Guid - %g\n", &HiiVariable->Guid)); 468 DEBUG ((EFI_D_INFO, " Name - %s\n", HiiVariable + 1)); 469 470 // 471 // For Hii Question header align. 472 // 473 HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->HeaderLength)); 474 while ((UINTN) HiiQuestion < ((UINTN) HiiVariable + HiiVariable->Length)) { 475 // 476 // Dump Hii Question related to the Hii Variable. 477 // 478 DumpHiiQuestion (HiiQuestion); 479 // 480 // For Hii Question header align. 481 // 482 HiiQuestion = (VAR_CHECK_HII_QUESTION_HEADER *) HEADER_ALIGN (((UINTN) HiiQuestion + HiiQuestion->Length)); 483 } 484 } 485 486 /** 487 Dump Var Check HII. 488 489 @param[in] VarCheckHiiBin Pointer to VarCheckHiiBin. 490 @param[in] VarCheckHiiBinSize VarCheckHiiBin size. 491 492 **/ 493 VOID 494 DumpVarCheckHii ( 495 IN VOID *VarCheckHiiBin, 496 IN UINTN VarCheckHiiBinSize 497 ) 498 { 499 VAR_CHECK_HII_VARIABLE_HEADER *HiiVariable; 500 501 DEBUG ((EFI_D_INFO, "DumpVarCheckHii\n")); 502 503 // 504 // For Hii Variable header align. 505 // 506 HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (VarCheckHiiBin); 507 while ((UINTN) HiiVariable < ((UINTN) VarCheckHiiBin + VarCheckHiiBinSize)) { 508 DumpHiiVariable (HiiVariable); 509 // 510 // For Hii Variable header align. 511 // 512 HiiVariable = (VAR_CHECK_HII_VARIABLE_HEADER *) HEADER_ALIGN (((UINTN) HiiVariable + HiiVariable->Length)); 513 } 514 } 515 #endif 516 517 /** 518 Constructor function of VarCheckHiiLib to register var check HII handler. 519 520 @param[in] ImageHandle The firmware allocated handle for the EFI image. 521 @param[in] SystemTable A pointer to the EFI System Table. 522 523 @retval EFI_SUCCESS The constructor executed correctly. 524 525 **/ 526 EFI_STATUS 527 EFIAPI 528 VarCheckHiiLibNullClassConstructor ( 529 IN EFI_HANDLE ImageHandle, 530 IN EFI_SYSTEM_TABLE *SystemTable 531 ) 532 { 533 VarCheckLibRegisterEndOfDxeCallback (VarCheckHiiGen); 534 VarCheckLibRegisterAddressPointer ((VOID **) &mVarCheckHiiBin); 535 VarCheckLibRegisterSetVariableCheckHandler (SetVariableCheckHandlerHii); 536 537 return EFI_SUCCESS; 538 } 539 540