MdeModulePkg/GptLib: Extract shareable GPT parser into a library

As reported in CVE-2024-13745 via oss-sec, DxeTpm2MeasureBootLib can
measure a partition table that differs from the one parsed by the
PartitionDxe driver.

To address this, the more complete GPT parsing logic from PartitionDxe
is extracted into a standalone GptLib library so it can be
shared between PartitionDxe and DxeTpm2MeasureBootLib. This ensures
that the exact same partition table measured into PCR[5] is the one
parsed and used by the system. PartitionDxe behavior is unchanged.

Ref: https://seclists.org/oss-sec/2026/q2/727
Signed-off-by: Richard Lyu <richard.lyu@suse.com>
This commit is contained in:
Richard Lyu 2026-06-25 14:17:28 +08:00 committed by mergify[bot]
parent 2938b830f6
commit 00a865d595
8 changed files with 707 additions and 590 deletions

View file

@ -0,0 +1,97 @@
/** @file
Shared GUID Partition Table (GPT) parsing and validation routines.
These routines decode and validate a disk partitioned with the GPT scheme
as described in the UEFI specification. They are shared between the
Partition driver (which installs child handles) and other consumers that
need to parse the same on-disk GPT layout.
Caution: These routines may receive untrusted input. The GPT partition
table is external input and must be validated carefully to avoid security
issues like buffer overflow and integer overflow.
Copyright (c) 2026, SUSE LLC. All rights reserved.<BR>
Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#pragma once
#include <Uefi.h>
#include <Guid/Gpt.h>
#include <Protocol/BlockIo.h>
#include <Protocol/DiskIo.h>
//
// GPT Partition Entry Status
//
typedef struct {
BOOLEAN OutOfRange;
BOOLEAN Overlap;
BOOLEAN OsSpecific;
} EFI_PARTITION_ENTRY_STATUS;
/**
Read GPT partition table header from the given LBA and validate it.
Caution: This function may receive untrusted input.
The GPT partition table header is external input, so this routine
will do basic validation for GPT partition table header before return.
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io protocol.
@param[in] Lba The starting Lba of the Partition Table.
@param[out] PartHeader Stores the partition table that is read.
@retval TRUE The partition table is valid.
@retval FALSE The partition table is not valid.
**/
BOOLEAN
PartitionValidGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_LBA Lba,
OUT EFI_PARTITION_TABLE_HEADER *PartHeader
);
/**
Restore Partition Table to its alternate place
(Primary -> Backup or Backup -> Primary).
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure.
@retval TRUE Restoring succeeds.
@retval FALSE Restoring failed.
**/
BOOLEAN
PartitionRestoreGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
);
/**
Check GPT partition entries and report the status of each entry.
Caution: This function may receive untrusted input.
The GPT partition entry is external input, so this routine
will do basic validation for GPT partition entry and report status.
@param[in] PartHeader Partition table header structure.
@param[in] PartEntry The partition entry array.
@param[out] PEntryStatus The partition entry status array
recording the status of each partition.
**/
VOID
PartitionCheckGptEntry (
IN EFI_PARTITION_TABLE_HEADER *PartHeader,
IN EFI_PARTITION_ENTRY *PartEntry,
OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
);

View file

@ -0,0 +1,548 @@
/** @file
Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
specification.
Caution: This file requires additional review when modified.
This driver will have external input - disk partition.
This external input must be validated carefully to avoid security issue like
buffer overflow, integer overflow.
PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
partition content and validate the GPT table and GPT entry.
Copyright (c) 2026, SUSE LLC. All rights reserved.<BR>
Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/GptLib.h>
/**
Check if the CRC field in the Partition table header is valid
for Partition entry array.
@param[in] BlockIo Parent BlockIo interface
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure
@retval TRUE the CRC is valid
@retval FALSE the CRC is invalid
**/
STATIC
BOOLEAN
PartitionCheckGptEntryArrayCRC (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
);
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Size The size of the table
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
STATIC
BOOLEAN
PartitionCheckCrcAltSize (
IN UINTN MaxSize,
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
STATIC
BOOLEAN
PartitionCheckCrc (
IN UINTN MaxSize,
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Updates the CRC32 value in the table header.
@param Size The size of the table
@param Hdr Table to update
**/
STATIC
VOID
PartitionSetCrcAltSize (
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Updates the CRC32 value in the table header.
@param Hdr Table to update
**/
STATIC
VOID
PartitionSetCrc (
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
This routine will read GPT partition table header and return it.
Caution: This function may receive untrusted input.
The GPT partition table header is external input, so this routine
will do basic validation for GPT partition table header before return.
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io protocol.
@param[in] Lba The starting Lba of the Partition Table
@param[out] PartHeader Stores the partition table that is read
@retval TRUE The partition table is valid
@retval FALSE The partition table is not valid
**/
BOOLEAN
PartitionValidGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_LBA Lba,
OUT EFI_PARTITION_TABLE_HEADER *PartHeader
)
{
EFI_STATUS Status;
UINT32 BlockSize;
EFI_PARTITION_TABLE_HEADER *PartHdr;
UINT32 MediaId;
BlockSize = BlockIo->Media->BlockSize;
MediaId = BlockIo->Media->MediaId;
PartHdr = AllocateZeroPool (BlockSize);
if (PartHdr == NULL) {
DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
return FALSE;
}
//
// Read the EFI Partition Table Header
//
Status = DiskIo->ReadDisk (
DiskIo,
MediaId,
MultU64x32 (Lba, BlockSize),
BlockSize,
PartHdr
);
if (EFI_ERROR (Status)) {
FreePool (PartHdr);
return FALSE;
}
if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
!PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
(PartHdr->MyLBA != Lba) ||
(PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
)
{
DEBUG ((DEBUG_INFO, "Invalid efi partition table header\n"));
FreePool (PartHdr);
return FALSE;
}
//
// Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
//
if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
FreePool (PartHdr);
return FALSE;
}
CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
FreePool (PartHdr);
return FALSE;
}
DEBUG ((DEBUG_INFO, " Valid efi partition table header\n"));
FreePool (PartHdr);
return TRUE;
}
/**
Check if the CRC field in the Partition table header is valid
for Partition entry array.
@param[in] BlockIo Parent BlockIo interface
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure
@retval TRUE the CRC is valid
@retval FALSE the CRC is invalid
**/
STATIC
BOOLEAN
PartitionCheckGptEntryArrayCRC (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
)
{
EFI_STATUS Status;
UINT8 *Ptr;
UINT32 Crc;
UINTN Size;
//
// Read the EFI Partition Entries
//
Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
if (Ptr == NULL) {
DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
return FALSE;
}
Status = DiskIo->ReadDisk (
DiskIo,
BlockIo->Media->MediaId,
MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (Ptr);
return FALSE;
}
Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
FreePool (Ptr);
return FALSE;
}
FreePool (Ptr);
return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
}
/**
Restore Partition Table to its alternate place
(Primary -> Backup or Backup -> Primary).
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure.
@retval TRUE Restoring succeeds
@retval FALSE Restoring failed
**/
BOOLEAN
PartitionRestoreGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
)
{
EFI_STATUS Status;
UINTN BlockSize;
EFI_PARTITION_TABLE_HEADER *PartHdr;
EFI_LBA PEntryLBA;
UINT8 *Ptr;
UINT32 MediaId;
PartHdr = NULL;
Ptr = NULL;
BlockSize = BlockIo->Media->BlockSize;
MediaId = BlockIo->Media->MediaId;
PartHdr = AllocateZeroPool (BlockSize);
if (PartHdr == NULL) {
DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
return FALSE;
}
PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
(PartHeader->LastUsableLBA + 1) : \
(PRIMARY_PART_HEADER_LBA + 1);
CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
PartHdr->MyLBA = PartHeader->AlternateLBA;
PartHdr->AlternateLBA = PartHeader->MyLBA;
PartHdr->PartitionEntryLBA = PEntryLBA;
PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
Status = DiskIo->WriteDisk (
DiskIo,
MediaId,
MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
BlockSize,
PartHdr
);
if (EFI_ERROR (Status)) {
goto Done;
}
Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
if (Ptr == NULL) {
DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
Status = DiskIo->ReadDisk (
DiskIo,
MediaId,
MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = DiskIo->WriteDisk (
DiskIo,
MediaId,
MultU64x32 (PEntryLBA, (UINT32)BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr
);
Done:
FreePool (PartHdr);
if (Ptr != NULL) {
FreePool (Ptr);
}
if (EFI_ERROR (Status)) {
return FALSE;
}
return TRUE;
}
/**
This routine will check GPT partition entry and return entry status.
Caution: This function may receive untrusted input.
The GPT partition entry is external input, so this routine
will do basic validation for GPT partition entry and report status.
@param[in] PartHeader Partition table header structure
@param[in] PartEntry The partition entry array
@param[out] PEntryStatus the partition entry status array
recording the status of each partition
**/
VOID
PartitionCheckGptEntry (
IN EFI_PARTITION_TABLE_HEADER *PartHeader,
IN EFI_PARTITION_ENTRY *PartEntry,
OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
)
{
EFI_LBA StartingLBA;
EFI_LBA EndingLBA;
EFI_PARTITION_ENTRY *Entry;
UINTN Index1;
UINTN Index2;
DEBUG ((DEBUG_INFO, " start check partition entries\n"));
for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
continue;
}
StartingLBA = Entry->StartingLBA;
EndingLBA = Entry->EndingLBA;
if ((StartingLBA > EndingLBA) ||
(StartingLBA < PartHeader->FirstUsableLBA) ||
(StartingLBA > PartHeader->LastUsableLBA) ||
(EndingLBA < PartHeader->FirstUsableLBA) ||
(EndingLBA > PartHeader->LastUsableLBA)
)
{
PEntryStatus[Index1].OutOfRange = TRUE;
continue;
}
if ((Entry->Attributes & BIT1) != 0) {
//
// If Bit 1 is set, this indicate that this is an OS specific GUID partition.
//
PEntryStatus[Index1].OsSpecific = TRUE;
}
for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
continue;
}
if ((Entry->EndingLBA >= StartingLBA) && (Entry->StartingLBA <= EndingLBA)) {
//
// This region overlaps with the Index1'th region
//
PEntryStatus[Index1].Overlap = TRUE;
PEntryStatus[Index2].Overlap = TRUE;
continue;
}
}
}
DEBUG ((DEBUG_INFO, " End check partition entries\n"));
}
/**
Updates the CRC32 value in the table header.
@param Hdr Table to update
**/
STATIC
VOID
PartitionSetCrc (
IN OUT EFI_TABLE_HEADER *Hdr
)
{
PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
}
/**
Updates the CRC32 value in the table header.
@param Size The size of the table
@param Hdr Table to update
**/
STATIC
VOID
PartitionSetCrcAltSize (
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
)
{
UINT32 Crc;
Hdr->CRC32 = 0;
gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
Hdr->CRC32 = Crc;
}
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
STATIC
BOOLEAN
PartitionCheckCrc (
IN UINTN MaxSize,
IN OUT EFI_TABLE_HEADER *Hdr
)
{
return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
}
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Size The size of the table
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
STATIC
BOOLEAN
PartitionCheckCrcAltSize (
IN UINTN MaxSize,
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
)
{
UINT32 Crc;
UINT32 OrgCrc;
EFI_STATUS Status;
Crc = 0;
if (Size == 0) {
//
// If header size is 0 CRC will pass so return FALSE here
//
return FALSE;
}
if ((MaxSize != 0) && (Size > MaxSize)) {
DEBUG ((DEBUG_ERROR, "CheckCrc32: Size > MaxSize\n"));
return FALSE;
}
//
// clear old crc from header
//
OrgCrc = Hdr->CRC32;
Hdr->CRC32 = 0;
Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc calculation failed\n"));
return FALSE;
}
//
// set results
//
Hdr->CRC32 = Crc;
//
// return status
//
DEBUG_CODE_BEGIN ();
if (OrgCrc != Crc) {
DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc check failed\n"));
}
DEBUG_CODE_END ();
return (BOOLEAN)(OrgCrc == Crc);
}

View file

@ -0,0 +1,49 @@
## @file
# Shared GUID Partition Table (GPT) parsing and validation library.
#
# Provides the GPT table parsing, validation and restore routines that are
# shared between the Partition driver and other consumers that must parse the
# same on-disk GPT layout.
#
# Caution: This library requires additional review when modified.
# This library will have external input - disk partition.
# This external input must be validated carefully to avoid security issue like
# buffer overflow, integer overflow.
#
# Copyright (c) 2026, SUSE LLC. All rights reserved.<BR>
# Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = GptLib
FILE_GUID = E228F30C-C7D5-4A93-BBA7-B4E22327E289
MODULE_TYPE = DXE_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = GptLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 EBC AARCH64 RISCV64 LOONGARCH64
#
[Sources]
Gpt.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
BaseLib
BaseMemoryLib
DebugLib
MemoryAllocationLib
UefiBootServicesTableLib
[Guids]
gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## GUID

View file

@ -32,6 +32,9 @@
Core/PrivateInclude
[LibraryClasses]
## @libraryclass Provides GPT partition table parsing and validation routines.
GptLib|Include/Library/GptLib.h
## @libraryclass Defines a set of methods to reset whole system.
ResetSystemLib|Include/Library/ResetSystemLib.h

View file

@ -46,6 +46,7 @@
PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
SortLib|MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
GptLib|MdeModulePkg/Library/GptLib/GptLib.inf
#
# UEFI & PI
#
@ -215,6 +216,7 @@
MdeModulePkg/Logo/Logo.inf
MdeModulePkg/Logo/LogoDxe.inf
MdeModulePkg/Library/BaseSortLib/BaseSortLib.inf
MdeModulePkg/Library/GptLib/GptLib.inf
MdeModulePkg/Library/BootDiscoveryPolicyUiLib/BootDiscoveryPolicyUiLib.inf
MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootMaintenanceManagerUiLib.inf
MdeModulePkg/Library/BootManagerUiLib/BootManagerUiLib.inf

View file

@ -1,6 +1,5 @@
/** @file
Decode a hard disk partitioned with the GPT scheme in the UEFI 2.0
specification.
Install GPT partition child handles for the Partition driver.
Caution: This file requires additional review when modified.
This driver will have external input - disk partition.
@ -8,10 +7,9 @@
buffer overflow, integer overflow.
PartitionInstallGptChildHandles() routine will read disk partition content and
do basic validation before PartitionInstallChildHandle().
PartitionValidGptTable(), PartitionCheckGptEntry() routine will accept disk
partition content and validate the GPT table and GPT entry.
do basic validation before PartitionInstallChildHandle(). The GPT table
parsing and validation helpers it relies on live in the shared GPT parser
(GptLib/Gpt.c).
Copyright (c) 2018 Qualcomm Datacenter Technologies, Inc.
Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
@ -21,146 +19,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "Partition.h"
/**
Install child handles if the Handle supports GPT partition structure.
Caution: This function may receive untrusted input.
The GPT partition table header is external input, so this routine
will do basic validation for GPT partition table header before return.
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io protocol.
@param[in] Lba The starting Lba of the Partition Table
@param[out] PartHeader Stores the partition table that is read
@retval TRUE The partition table is valid
@retval FALSE The partition table is not valid
**/
BOOLEAN
PartitionValidGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_LBA Lba,
OUT EFI_PARTITION_TABLE_HEADER *PartHeader
);
/**
Check if the CRC field in the Partition table header is valid
for Partition entry array.
@param[in] BlockIo Parent BlockIo interface
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure
@retval TRUE the CRC is valid
@retval FALSE the CRC is invalid
**/
BOOLEAN
PartitionCheckGptEntryArrayCRC (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
);
/**
Restore Partition Table to its alternate place
(Primary -> Backup or Backup -> Primary).
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure.
@retval TRUE Restoring succeeds
@retval FALSE Restoring failed
**/
BOOLEAN
PartitionRestoreGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
);
/**
This routine will check GPT partition entry and return entry status.
Caution: This function may receive untrusted input.
The GPT partition entry is external input, so this routine
will do basic validation for GPT partition entry and report status.
@param[in] PartHeader Partition table header structure
@param[in] PartEntry The partition entry array
@param[out] PEntryStatus the partition entry status array
recording the status of each partition
**/
VOID
PartitionCheckGptEntry (
IN EFI_PARTITION_TABLE_HEADER *PartHeader,
IN EFI_PARTITION_ENTRY *PartEntry,
OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
);
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Size The size of the table
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
BOOLEAN
PartitionCheckCrcAltSize (
IN UINTN MaxSize,
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
BOOLEAN
PartitionCheckCrc (
IN UINTN MaxSize,
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Updates the CRC32 value in the table header.
@param Size The size of the table
@param Hdr Table to update
**/
VOID
PartitionSetCrcAltSize (
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Updates the CRC32 value in the table header.
@param Hdr Table to update
**/
VOID
PartitionSetCrc (
IN OUT EFI_TABLE_HEADER *Hdr
);
/**
Install child handles if the Handle supports GPT partition structure.
@ -446,438 +304,3 @@ Done:
return GptValidStatus;
}
/**
This routine will read GPT partition table header and return it.
Caution: This function may receive untrusted input.
The GPT partition table header is external input, so this routine
will do basic validation for GPT partition table header before return.
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io protocol.
@param[in] Lba The starting Lba of the Partition Table
@param[out] PartHeader Stores the partition table that is read
@retval TRUE The partition table is valid
@retval FALSE The partition table is not valid
**/
BOOLEAN
PartitionValidGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_LBA Lba,
OUT EFI_PARTITION_TABLE_HEADER *PartHeader
)
{
EFI_STATUS Status;
UINT32 BlockSize;
EFI_PARTITION_TABLE_HEADER *PartHdr;
UINT32 MediaId;
BlockSize = BlockIo->Media->BlockSize;
MediaId = BlockIo->Media->MediaId;
PartHdr = AllocateZeroPool (BlockSize);
if (PartHdr == NULL) {
DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
return FALSE;
}
//
// Read the EFI Partition Table Header
//
Status = DiskIo->ReadDisk (
DiskIo,
MediaId,
MultU64x32 (Lba, BlockSize),
BlockSize,
PartHdr
);
if (EFI_ERROR (Status)) {
FreePool (PartHdr);
return FALSE;
}
if ((PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
!PartitionCheckCrc (BlockSize, &PartHdr->Header) ||
(PartHdr->MyLBA != Lba) ||
(PartHdr->SizeOfPartitionEntry < sizeof (EFI_PARTITION_ENTRY))
)
{
DEBUG ((DEBUG_INFO, "Invalid efi partition table header\n"));
FreePool (PartHdr);
return FALSE;
}
//
// Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
//
if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
FreePool (PartHdr);
return FALSE;
}
CopyMem (PartHeader, PartHdr, sizeof (EFI_PARTITION_TABLE_HEADER));
if (!PartitionCheckGptEntryArrayCRC (BlockIo, DiskIo, PartHeader)) {
FreePool (PartHdr);
return FALSE;
}
DEBUG ((DEBUG_INFO, " Valid efi partition table header\n"));
FreePool (PartHdr);
return TRUE;
}
/**
Check if the CRC field in the Partition table header is valid
for Partition entry array.
@param[in] BlockIo Parent BlockIo interface
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure
@retval TRUE the CRC is valid
@retval FALSE the CRC is invalid
**/
BOOLEAN
PartitionCheckGptEntryArrayCRC (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
)
{
EFI_STATUS Status;
UINT8 *Ptr;
UINT32 Crc;
UINTN Size;
//
// Read the EFI Partition Entries
//
Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
if (Ptr == NULL) {
DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
return FALSE;
}
Status = DiskIo->ReadDisk (
DiskIo,
BlockIo->Media->MediaId,
MultU64x32 (PartHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr
);
if (EFI_ERROR (Status)) {
FreePool (Ptr);
return FALSE;
}
Size = PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry;
Status = gBS->CalculateCrc32 (Ptr, Size, &Crc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CheckPEntryArrayCRC: Crc calculation failed\n"));
FreePool (Ptr);
return FALSE;
}
FreePool (Ptr);
return (BOOLEAN)(PartHeader->PartitionEntryArrayCRC32 == Crc);
}
/**
Restore Partition Table to its alternate place
(Primary -> Backup or Backup -> Primary).
@param[in] BlockIo Parent BlockIo interface.
@param[in] DiskIo Disk Io Protocol.
@param[in] PartHeader Partition table header structure.
@retval TRUE Restoring succeeds
@retval FALSE Restoring failed
**/
BOOLEAN
PartitionRestoreGptTable (
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
IN EFI_DISK_IO_PROTOCOL *DiskIo,
IN EFI_PARTITION_TABLE_HEADER *PartHeader
)
{
EFI_STATUS Status;
UINTN BlockSize;
EFI_PARTITION_TABLE_HEADER *PartHdr;
EFI_LBA PEntryLBA;
UINT8 *Ptr;
UINT32 MediaId;
PartHdr = NULL;
Ptr = NULL;
BlockSize = BlockIo->Media->BlockSize;
MediaId = BlockIo->Media->MediaId;
PartHdr = AllocateZeroPool (BlockSize);
if (PartHdr == NULL) {
DEBUG ((DEBUG_ERROR, "Allocate pool error\n"));
return FALSE;
}
PEntryLBA = (PartHeader->MyLBA == PRIMARY_PART_HEADER_LBA) ? \
(PartHeader->LastUsableLBA + 1) : \
(PRIMARY_PART_HEADER_LBA + 1);
CopyMem (PartHdr, PartHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
PartHdr->MyLBA = PartHeader->AlternateLBA;
PartHdr->AlternateLBA = PartHeader->MyLBA;
PartHdr->PartitionEntryLBA = PEntryLBA;
PartitionSetCrc ((EFI_TABLE_HEADER *)PartHdr);
Status = DiskIo->WriteDisk (
DiskIo,
MediaId,
MultU64x32 (PartHdr->MyLBA, (UINT32)BlockSize),
BlockSize,
PartHdr
);
if (EFI_ERROR (Status)) {
goto Done;
}
Ptr = AllocatePool (PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry);
if (Ptr == NULL) {
DEBUG ((DEBUG_ERROR, " Allocate pool error\n"));
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
Status = DiskIo->ReadDisk (
DiskIo,
MediaId,
MultU64x32 (PartHeader->PartitionEntryLBA, (UINT32)BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr
);
if (EFI_ERROR (Status)) {
goto Done;
}
Status = DiskIo->WriteDisk (
DiskIo,
MediaId,
MultU64x32 (PEntryLBA, (UINT32)BlockSize),
PartHeader->NumberOfPartitionEntries * PartHeader->SizeOfPartitionEntry,
Ptr
);
Done:
FreePool (PartHdr);
if (Ptr != NULL) {
FreePool (Ptr);
}
if (EFI_ERROR (Status)) {
return FALSE;
}
return TRUE;
}
/**
This routine will check GPT partition entry and return entry status.
Caution: This function may receive untrusted input.
The GPT partition entry is external input, so this routine
will do basic validation for GPT partition entry and report status.
@param[in] PartHeader Partition table header structure
@param[in] PartEntry The partition entry array
@param[out] PEntryStatus the partition entry status array
recording the status of each partition
**/
VOID
PartitionCheckGptEntry (
IN EFI_PARTITION_TABLE_HEADER *PartHeader,
IN EFI_PARTITION_ENTRY *PartEntry,
OUT EFI_PARTITION_ENTRY_STATUS *PEntryStatus
)
{
EFI_LBA StartingLBA;
EFI_LBA EndingLBA;
EFI_PARTITION_ENTRY *Entry;
UINTN Index1;
UINTN Index2;
DEBUG ((DEBUG_INFO, " start check partition entries\n"));
for (Index1 = 0; Index1 < PartHeader->NumberOfPartitionEntries; Index1++) {
Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index1 * PartHeader->SizeOfPartitionEntry);
if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
continue;
}
StartingLBA = Entry->StartingLBA;
EndingLBA = Entry->EndingLBA;
if ((StartingLBA > EndingLBA) ||
(StartingLBA < PartHeader->FirstUsableLBA) ||
(StartingLBA > PartHeader->LastUsableLBA) ||
(EndingLBA < PartHeader->FirstUsableLBA) ||
(EndingLBA > PartHeader->LastUsableLBA)
)
{
PEntryStatus[Index1].OutOfRange = TRUE;
continue;
}
if ((Entry->Attributes & BIT1) != 0) {
//
// If Bit 1 is set, this indicate that this is an OS specific GUID partition.
//
PEntryStatus[Index1].OsSpecific = TRUE;
}
for (Index2 = Index1 + 1; Index2 < PartHeader->NumberOfPartitionEntries; Index2++) {
Entry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartEntry + Index2 * PartHeader->SizeOfPartitionEntry);
if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
continue;
}
if ((Entry->EndingLBA >= StartingLBA) && (Entry->StartingLBA <= EndingLBA)) {
//
// This region overlaps with the Index1'th region
//
PEntryStatus[Index1].Overlap = TRUE;
PEntryStatus[Index2].Overlap = TRUE;
continue;
}
}
}
DEBUG ((DEBUG_INFO, " End check partition entries\n"));
}
/**
Updates the CRC32 value in the table header.
@param Hdr Table to update
**/
VOID
PartitionSetCrc (
IN OUT EFI_TABLE_HEADER *Hdr
)
{
PartitionSetCrcAltSize (Hdr->HeaderSize, Hdr);
}
/**
Updates the CRC32 value in the table header.
@param Size The size of the table
@param Hdr Table to update
**/
VOID
PartitionSetCrcAltSize (
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
)
{
UINT32 Crc;
Hdr->CRC32 = 0;
gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
Hdr->CRC32 = Crc;
}
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
BOOLEAN
PartitionCheckCrc (
IN UINTN MaxSize,
IN OUT EFI_TABLE_HEADER *Hdr
)
{
return PartitionCheckCrcAltSize (MaxSize, Hdr->HeaderSize, Hdr);
}
/**
Checks the CRC32 value in the table header.
@param MaxSize Max Size limit
@param Size The size of the table
@param Hdr Table to check
@return TRUE CRC Valid
@return FALSE CRC Invalid
**/
BOOLEAN
PartitionCheckCrcAltSize (
IN UINTN MaxSize,
IN UINTN Size,
IN OUT EFI_TABLE_HEADER *Hdr
)
{
UINT32 Crc;
UINT32 OrgCrc;
EFI_STATUS Status;
Crc = 0;
if (Size == 0) {
//
// If header size is 0 CRC will pass so return FALSE here
//
return FALSE;
}
if ((MaxSize != 0) && (Size > MaxSize)) {
DEBUG ((DEBUG_ERROR, "CheckCrc32: Size > MaxSize\n"));
return FALSE;
}
//
// clear old crc from header
//
OrgCrc = Hdr->CRC32;
Hdr->CRC32 = 0;
Status = gBS->CalculateCrc32 ((UINT8 *)Hdr, Size, &Crc);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc calculation failed\n"));
return FALSE;
}
//
// set results
//
Hdr->CRC32 = Crc;
//
// return status
//
DEBUG_CODE_BEGIN ();
if (OrgCrc != Crc) {
DEBUG ((DEBUG_ERROR, "CheckCrc32: Crc check failed\n"));
}
DEBUG_CODE_END ();
return (BOOLEAN)(OrgCrc == Crc);
}

View file

@ -31,6 +31,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/GptLib.h>
#include <IndustryStandard/Mbr.h>
#include <IndustryStandard/ElTorito.h>
#include <IndustryStandard/Udf.h>
@ -93,15 +95,6 @@ extern EFI_COMPONENT_NAME2_PROTOCOL gPartitionComponentName2;
(((UINT8 *) a)[2] << 16) | \
(((UINT8 *) a)[3] << 24) )
//
// GPT Partition Entry Status
//
typedef struct {
BOOLEAN OutOfRange;
BOOLEAN Overlap;
BOOLEAN OsSpecific;
} EFI_PARTITION_ENTRY_STATUS;
//
// Function Prototypes
//

View file

@ -47,10 +47,12 @@
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
DevicePathLib
GptLib
UefiBootServicesTableLib
MemoryAllocationLib
BaseMemoryLib