/** Check the integrity of the capsule descriptors. @param BlockList Pointer to the capsule descriptors @retval NULL BlockList is not valid. @retval LastBlockDesc Last one Block in BlockList **/ EFI_CAPSULE_BLOCK_DESCRIPTOR * ValidateCapsuleIntegrity ( IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList ) { EFI_CAPSULE_HEADER *CapsuleHeader; UINT64 CapsuleSize; UINTN CapsuleCount; EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr; DEBUG ((EFI_D_INFO, "ValidateCapsuleIntegrity\n")); // // Go through the list to look for inconsistencies. Check for: // * misaligned block descriptors. // * The first capsule header guid // * The first capsule header flag // * The first capsule header HeaderSize // * Length > MAX_ADDRESS // * ContinuationPointer > MAX_ADDRESS // * DataBlock + Length > MAX_ADDRESS // CapsuleSize = 0; CapsuleCount = 0; Ptr = BlockList; DEBUG ((EFI_D_INFO, "Ptr - 0x%x\n", Ptr)); DEBUG ((EFI_D_INFO, "Ptr->Length - 0x%x\n", Ptr->Length)); DEBUG ((EFI_D_INFO, "Ptr->Union - 0x%x\n", Ptr->Union.ContinuationPointer)); while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { // // Make sure the descriptor is aligned at UINT64 in memory // if ((UINTN) Ptr & (sizeof(UINT64) - 1)) { DEBUG ((EFI_D_ERROR, "ERROR: BlockList address failed alignment check\n")); return NULL; } // // Sanity Check // if (Ptr->Length > MAX_ADDRESS) { DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Length(0x%lx) > MAX_ADDRESS\n", Ptr->Length)); return NULL; } if (Ptr->Length == 0) { // // Sanity Check // if (Ptr->Union.ContinuationPointer > MAX_ADDRESS) { DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Union.ContinuationPointer(0x%lx) > MAX_ADDRESS\n", Ptr->Union.ContinuationPointer)); return NULL; } // // Descriptor points to another list of block descriptors somewhere // else. // Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer; DEBUG ((EFI_D_INFO, "Ptr(C) - 0x%x\n", Ptr)); DEBUG ((EFI_D_INFO, "Ptr->Length - 0x%x\n", Ptr->Length)); DEBUG ((EFI_D_INFO, "Ptr->Union - 0x%x\n", Ptr->Union.ContinuationPointer)); } else { // // Sanity Check // if (Ptr->Union.DataBlock > (MAX_ADDRESS - (UINTN)Ptr->Length)) { DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Union.DataBlock(0x%lx) > (MAX_ADDRESS - (UINTN)Ptr->Length(0x%lx))\n", Ptr->Union.DataBlock, Ptr->Length)); return NULL; } // //To enhance the reliability of check-up, the first capsule's header is checked here. //More reliabilities check-up will do later. // if (CapsuleSize == 0) { // //Move to the first capsule to check its header. // CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock); // // Sanity check // if (Ptr->Length < sizeof(EFI_CAPSULE_HEADER)) { DEBUG ((EFI_D_ERROR, "ERROR: Ptr->Length(0x%lx) < sizeof(EFI_CAPSULE_HEADER)\n", Ptr->Length)); return NULL; } // // Make sure HeaderSize field is valid // if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) { DEBUG ((EFI_D_ERROR, "ERROR: CapsuleHeader->HeaderSize(0x%x) > CapsuleHeader->CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize)); return NULL; } if (IsCapsuleCorrupted (CapsuleHeader)) { return NULL; } CapsuleCount ++; CapsuleSize = CapsuleHeader->CapsuleImageSize; } if (CapsuleSize >= Ptr->Length) { CapsuleSize = CapsuleSize - Ptr->Length; } else { DEBUG ((EFI_D_ERROR, "ERROR: CapsuleSize(0x%lx) < Ptr->Length(0x%lx)\n", CapsuleSize, Ptr->Length)); // // Sanity check // return NULL; } // // Move to next BLOCK descriptor // Ptr++; DEBUG ((EFI_D_INFO, "Ptr(B) - 0x%x\n", Ptr)); DEBUG ((EFI_D_INFO, "Ptr->Length - 0x%x\n", Ptr->Length)); DEBUG ((EFI_D_INFO, "Ptr->Union - 0x%x\n", Ptr->Union.ContinuationPointer)); } } if (CapsuleCount == 0) { // // No any capsule is found in BlockList // DEBUG ((EFI_D_ERROR, "ERROR: CapsuleCount(0x%x) == 0\n", CapsuleCount)); return NULL; } if (CapsuleSize != 0) { // // Capsule data is incomplete. // DEBUG ((EFI_D_ERROR, "ERROR: CapsuleSize(0x%lx) != 0\n", CapsuleSize)); return NULL; } return Ptr; }
/** Check the integrity of the capsule descriptors. @param BlockList Pointer to the capsule descriptors @retval NULL BlockList is not valid. @retval LastBlockDesc Last one Block in BlockList **/ EFI_CAPSULE_BLOCK_DESCRIPTOR * ValidateCapsuleIntegrity ( IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockList ) { EFI_CAPSULE_HEADER *CapsuleHeader; UINT64 CapsuleSize; UINT32 CapsuleCount; EFI_CAPSULE_BLOCK_DESCRIPTOR *Ptr; // // Go through the list to look for inconsistencies. Check for: // * misaligned block descriptors. // * The first capsule header guid // * The first capsule header flag // * Data + Length < Data (wrap) CapsuleSize = 0; CapsuleCount = 0; Ptr = BlockList; while ((Ptr->Length != 0) || (Ptr->Union.ContinuationPointer != (EFI_PHYSICAL_ADDRESS) (UINTN) NULL)) { // // Make sure the descriptor is aligned at UINT64 in memory // if ((UINTN) Ptr & 0x07) { DEBUG ((EFI_D_ERROR, "BlockList address failed alignment check\n")); return NULL; } if (Ptr->Length == 0) { // // Descriptor points to another list of block descriptors somewhere // else. // Ptr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) Ptr->Union.ContinuationPointer; } else { // //To enhance the reliability of check-up, the first capsule's header is checked here. //More reliabilities check-up will do later. // if (CapsuleSize == 0) { // //Move to the first capsule to check its header. // CapsuleHeader = (EFI_CAPSULE_HEADER*)((UINTN)Ptr->Union.DataBlock); if (IsCapsuleCorrupted (CapsuleHeader)) { return NULL; } CapsuleCount ++; CapsuleSize = CapsuleHeader->CapsuleImageSize; } if (CapsuleSize >= Ptr->Length) { CapsuleSize = CapsuleSize - Ptr->Length; } else { CapsuleSize = 0; } // // Move to next BLOCK descriptor // Ptr++; } } if ((CapsuleCount == 0) || (CapsuleSize != 0)) { // // No any capsule is found in BlockList or capsule data is corrupted. // return NULL; } return Ptr; }