mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
Add the positive-path host-based tests for the shared GptLib parser (extracted as part of the parser security hardening), ensuring the tightened checks in PartitionValidGptTable(), PartitionCheckGptEntry() and PartitionRestoreGptTable() do not falsely reject well-formed GPTs. The tests run against an in-memory mock disk and cover accepted primary/backup headers, boundary but legal header/entry sizes, correct entry-status flagging on valid entries, and primary/backup restore round-trips. Signed-off-by: Richard Lyu <richard.lyu@suse.com>
298 lines
8.9 KiB
C
298 lines
8.9 KiB
C
/** @file
|
|
Shared mock disk and GPT construction helpers used by the GptLib
|
|
host-based unit tests.
|
|
|
|
Copyright (c) 2026, SUSE LLC. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include "GptLibUnitTestCommon.h"
|
|
|
|
UINT8 mDiskImage[DISK_IMAGE_SIZE];
|
|
|
|
EFI_BLOCK_IO_MEDIA mBlockIoMedia;
|
|
EFI_BLOCK_IO_PROTOCOL mBlockIo;
|
|
EFI_DISK_IO_PROTOCOL mDiskIo;
|
|
BOOLEAN mWriteProtected;
|
|
|
|
CONST EFI_GUID mEspTypeGuid = {
|
|
0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }
|
|
};
|
|
|
|
CONST EFI_GUID mPartitionGuid1 = {
|
|
0x11111111, 0x2222, 0x3333, { 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77 }
|
|
};
|
|
|
|
CONST EFI_GUID mPartitionGuid2 = {
|
|
0x88888888, 0x9999, 0xAAAA, { 0xBB, 0xBB, 0xCC, 0xCC, 0xDD, 0xDD, 0xEE, 0xEE }
|
|
};
|
|
|
|
/**
|
|
Mock implementation of EFI_DISK_IO_PROTOCOL.ReadDisk backed by the in-memory
|
|
disk image.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_IO_PROTOCOL instance.
|
|
@param[in] MediaId ID of the medium to read from.
|
|
@param[in] Offset Starting byte offset on the logical disk.
|
|
@param[in] BufferSize Number of bytes to read.
|
|
@param[out] Buffer Buffer into which the data is read.
|
|
|
|
@retval EFI_SUCCESS The data was read successfully.
|
|
@retval EFI_DEVICE_ERROR The request was invalid or out of range.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MockReadDisk (
|
|
IN EFI_DISK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN UINT64 Offset,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
if ((Buffer == NULL) ||
|
|
(MediaId != mBlockIoMedia.MediaId) ||
|
|
(Offset > DISK_IMAGE_SIZE) ||
|
|
(BufferSize > (DISK_IMAGE_SIZE - Offset)))
|
|
{
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
CopyMem (Buffer, mDiskImage + Offset, BufferSize);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Mock implementation of EFI_DISK_IO_PROTOCOL.WriteDisk backed by the in-memory
|
|
disk image, honoring the write-protected flag.
|
|
|
|
@param[in] This Pointer to the EFI_DISK_IO_PROTOCOL instance.
|
|
@param[in] MediaId ID of the medium to write to.
|
|
@param[in] Offset Starting byte offset on the logical disk.
|
|
@param[in] BufferSize Number of bytes to write.
|
|
@param[in] Buffer Buffer holding the data to write.
|
|
|
|
@retval EFI_SUCCESS The data was written successfully.
|
|
@retval EFI_WRITE_PROTECTED The mock medium is write-protected.
|
|
@retval EFI_DEVICE_ERROR The request was invalid or out of range.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
MockWriteDisk (
|
|
IN EFI_DISK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN UINT64 Offset,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
if (mWriteProtected) {
|
|
return EFI_WRITE_PROTECTED;
|
|
}
|
|
|
|
if ((Buffer == NULL) ||
|
|
(MediaId != mBlockIoMedia.MediaId) ||
|
|
(Offset > DISK_IMAGE_SIZE) ||
|
|
(BufferSize > (DISK_IMAGE_SIZE - Offset)))
|
|
{
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
CopyMem (mDiskImage + Offset, Buffer, BufferSize);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Return a pointer into the in-memory disk image at the given LBA.
|
|
|
|
@param[in] Lba Logical block address to locate.
|
|
|
|
@return Pointer to the start of the requested block within the disk image.
|
|
**/
|
|
UINT8 *
|
|
GetDiskLba (
|
|
IN EFI_LBA Lba
|
|
)
|
|
{
|
|
return mDiskImage + (UINTN)(Lba * SECTOR_SIZE);
|
|
}
|
|
|
|
/**
|
|
Return a pointer to the primary GPT header within the in-memory disk image.
|
|
|
|
@return Pointer to the primary EFI_PARTITION_TABLE_HEADER.
|
|
**/
|
|
EFI_PARTITION_TABLE_HEADER *
|
|
GetPrimaryHeader (
|
|
VOID
|
|
)
|
|
{
|
|
return (EFI_PARTITION_TABLE_HEADER *)(VOID *)GetDiskLba (PRIMARY_PART_HEADER_LBA);
|
|
}
|
|
|
|
/**
|
|
Recompute and store the header CRC32 for the given GPT header.
|
|
|
|
@param[in,out] Header The GPT header whose CRC32 field is updated.
|
|
**/
|
|
VOID
|
|
UpdateGptHeaderCrc (
|
|
IN OUT EFI_PARTITION_TABLE_HEADER *Header
|
|
)
|
|
{
|
|
Header->Header.CRC32 = 0;
|
|
Header->Header.CRC32 = CalculateCrc32 (Header, Header->Header.HeaderSize);
|
|
}
|
|
|
|
/**
|
|
Populate a partition entry with the ESP type GUID and the given attributes.
|
|
|
|
@param[in,out] Entry The partition entry to fill.
|
|
@param[in] UniquePartitionGuid Unique partition GUID to assign.
|
|
@param[in] StartingLba Starting LBA of the partition.
|
|
@param[in] EndingLba Ending LBA of the partition.
|
|
**/
|
|
VOID
|
|
FillPartitionEntry (
|
|
IN OUT EFI_PARTITION_ENTRY *Entry,
|
|
IN CONST EFI_GUID *UniquePartitionGuid,
|
|
IN EFI_LBA StartingLba,
|
|
IN EFI_LBA EndingLba
|
|
)
|
|
{
|
|
CopyGuid (&Entry->PartitionTypeGUID, &mEspTypeGuid);
|
|
CopyGuid (&Entry->UniquePartitionGUID, UniquePartitionGuid);
|
|
Entry->StartingLBA = StartingLba;
|
|
Entry->EndingLBA = EndingLba;
|
|
}
|
|
|
|
/**
|
|
Construct a complete GPT header and partition entry array at the given LBA in
|
|
the in-memory disk image, recalculating all CRCs.
|
|
|
|
@param[in] HeaderLba LBA at which to write the GPT header.
|
|
@param[in] AlternateLba Value stored in the header AlternateLBA field.
|
|
@param[in] EntryArrayLba LBA at which to write the partition entry array.
|
|
@param[in] NumEntries Number of partition entries in the array.
|
|
@param[in] EntrySize Size in bytes of each partition entry.
|
|
@param[in] NumPartitions Number of populated partition entries.
|
|
**/
|
|
VOID
|
|
WriteGptTableAt (
|
|
IN EFI_LBA HeaderLba,
|
|
IN EFI_LBA AlternateLba,
|
|
IN EFI_LBA EntryArrayLba,
|
|
IN UINT32 NumEntries,
|
|
IN UINT32 EntrySize,
|
|
IN UINT32 NumPartitions
|
|
)
|
|
{
|
|
EFI_PARTITION_TABLE_HEADER *Header;
|
|
UINT8 *Array;
|
|
UINT32 ArraySize;
|
|
|
|
ArraySize = NumEntries * EntrySize;
|
|
Array = GetDiskLba (EntryArrayLba);
|
|
ZeroMem (Array, ArraySize);
|
|
if (NumPartitions >= 1) {
|
|
FillPartitionEntry ((EFI_PARTITION_ENTRY *)(VOID *)Array, &mPartitionGuid1, 34, 133);
|
|
}
|
|
|
|
if (NumPartitions >= 2) {
|
|
FillPartitionEntry ((EFI_PARTITION_ENTRY *)(VOID *)(Array + EntrySize), &mPartitionGuid2, 134, 233);
|
|
}
|
|
|
|
Header = (EFI_PARTITION_TABLE_HEADER *)(VOID *)GetDiskLba (HeaderLba);
|
|
ZeroMem (Header, SECTOR_SIZE);
|
|
Header->Header.Signature = EFI_PTAB_HEADER_ID;
|
|
Header->Header.Revision = TEST_GPT_REVISION_V1;
|
|
Header->Header.HeaderSize = sizeof (EFI_PARTITION_TABLE_HEADER);
|
|
Header->MyLBA = HeaderLba;
|
|
Header->AlternateLBA = AlternateLba;
|
|
Header->FirstUsableLBA = FIRST_USABLE_LBA;
|
|
Header->LastUsableLBA = LAST_USABLE_LBA;
|
|
Header->PartitionEntryLBA = EntryArrayLba;
|
|
Header->NumberOfPartitionEntries = NumEntries;
|
|
Header->SizeOfPartitionEntry = EntrySize;
|
|
Header->PartitionEntryArrayCRC32 = CalculateCrc32 (Array, ArraySize);
|
|
UpdateGptHeaderCrc (Header);
|
|
}
|
|
|
|
/**
|
|
Reset the mock disk and protocol state and lay down a valid primary GPT.
|
|
**/
|
|
VOID
|
|
SetupDiskWithValidPrimary (
|
|
VOID
|
|
)
|
|
{
|
|
ZeroMem (mDiskImage, sizeof (mDiskImage));
|
|
|
|
ZeroMem (&mBlockIoMedia, sizeof (mBlockIoMedia));
|
|
mBlockIoMedia.MediaId = 1;
|
|
mBlockIoMedia.BlockSize = SECTOR_SIZE;
|
|
mBlockIoMedia.LastBlock = LAST_LBA;
|
|
|
|
ZeroMem (&mBlockIo, sizeof (mBlockIo));
|
|
mBlockIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
|
|
mBlockIo.Media = &mBlockIoMedia;
|
|
|
|
ZeroMem (&mDiskIo, sizeof (mDiskIo));
|
|
mDiskIo.Revision = EFI_DISK_IO_PROTOCOL_REVISION;
|
|
mDiskIo.ReadDisk = MockReadDisk;
|
|
mDiskIo.WriteDisk = MockWriteDisk;
|
|
|
|
mWriteProtected = FALSE;
|
|
|
|
WriteGptTableAt (
|
|
PRIMARY_PART_HEADER_LBA,
|
|
LAST_LBA,
|
|
PRIMARY_PART_HEADER_LBA + 1,
|
|
NUM_PARTITION_ENTRIES,
|
|
PARTITION_ENTRY_SIZE,
|
|
2
|
|
);
|
|
}
|
|
|
|
/**
|
|
Invoke PartitionValidGptTable against the mock disk at the given LBA.
|
|
|
|
@param[in] Lba LBA of the GPT header to validate.
|
|
@param[out] Header Buffer to receive the validated GPT header.
|
|
|
|
@retval TRUE The GPT table at Lba is valid.
|
|
@retval FALSE The GPT table at Lba is invalid.
|
|
**/
|
|
BOOLEAN
|
|
ValidateAt (
|
|
IN EFI_LBA Lba,
|
|
OUT EFI_PARTITION_TABLE_HEADER *Header
|
|
)
|
|
{
|
|
return PartitionValidGptTable (&mBlockIo, &mDiskIo, Lba, Header);
|
|
}
|
|
|
|
/**
|
|
Initialize a GPT header in memory for PartitionCheckGptEntry tests.
|
|
|
|
@param[out] Header The GPT header to initialize.
|
|
@param[in] NumEntries Number of partition entries to record.
|
|
@param[in] EntrySize Size in bytes of each partition entry.
|
|
**/
|
|
VOID
|
|
InitCheckEntryHeader (
|
|
OUT EFI_PARTITION_TABLE_HEADER *Header,
|
|
IN UINT32 NumEntries,
|
|
IN UINT32 EntrySize
|
|
)
|
|
{
|
|
ZeroMem (Header, sizeof (*Header));
|
|
Header->FirstUsableLBA = FIRST_USABLE_LBA;
|
|
Header->LastUsableLBA = 200;
|
|
Header->NumberOfPartitionEntries = NumEntries;
|
|
Header->SizeOfPartitionEntry = EntrySize;
|
|
}
|