Esempio n. 1
0
/**
  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;
}