Skip to content

[Bug] malformed GPT entry with ending_lba < starting_lba creates an underflowed partition size #11271

@XueDugu

Description

@XueDugu

RT-Thread Version

master (verified on commit 2b58dec87b584aa7ded6e8c736498716f8d29cd0)

Hardware Type/Architectures

any BSP using the new block partition probing path with EFI/GPT enabled

Develop Toolchain

GCC

Describe the bug

GPT Partition Entry Underflow in RT-Thread EFI/GPT Parser

Affected Components

Field Detail
File 1 components/drivers/block/partitions/efi.c
File 2 components/drivers/block/blk_partition.c
Function 1 rt_inline rt_bool_t is_pte_valid(const gpt_entry *pte, const rt_size_t lastlba)
Function 2 rt_err_t efi_partition(struct rt_blk_disk *disk)
Function 3 rt_err_t blk_put_partition(struct rt_blk_disk *disk, const char *type, rt_size_t start, rt_size_t count, int partno)

Vulnerability Details

1. GPT entries accepted without checking ending_lba >= starting_lba

In efi.c, GPT entries are considered valid by is_pte_valid() if:

  • partition_type_guid is not NULL_GUID
  • starting_lba <= lastlba
  • ending_lba <= lastlba

Current code:

rt_inline rt_bool_t is_pte_valid(const gpt_entry *pte, const rt_size_t lastlba)
{
    if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
        rt_le64_to_cpu(pte->starting_lba) > lastlba ||
        rt_le64_to_cpu(pte->ending_lba) > lastlba)
    {
        return RT_FALSE;
    }

    return RT_TRUE;
}

There is no check that ending_lba >= starting_lba. So a malformed GPT entry with:

  • starting_lba inside disk bounds
  • ending_lba inside disk bounds
  • but ending_lba < starting_lba

is still accepted as valid.


2. Partition size calculation underflows

efi_partition() computes the partition length as:

rt_uint64_t start = rt_le64_to_cpu(ptes[i].starting_lba);
rt_uint64_t size = rt_le64_to_cpu(ptes[i].ending_lba) -
        rt_le64_to_cpu(ptes[i].starting_lba) + 1ULL;

If ending_lba < starting_lba, the subtraction underflows in unsigned arithmetic and produces a very large wrapped size.

That underflowed size is then passed to blk_put_partition():

blk_put_partition(disk, "gpt", start, size, i)

and stored into the logical partition device:

blk->sector_start = start;
blk->sector_count = count;
blk->partition.offset = start;
blk->partition.size = count;

As a result, a malformed GPT entry can create a logical partition object with an attacker-controlled start and a huge wrapped size.


Trigger Condition

The bug is reached during normal GPT partition probing:

rt_blk_disk_probe_partition()
    -> efi_partition()
        -> find_valid_gpt()
        -> iterate GPT entries
        -> is_pte_valid()
        -> size = ending_lba - starting_lba + 1ULL
        -> blk_put_partition(...)

No local code changes are required. A crafted GPT image with valid headers/CRCs and a malformed partition entry is sufficient.

ℹ️ This appears to be distinct from the already reported GPT allocation bug in #11260.


Proof of Concept

A PoC can be implemented with a crafted GPT disk image used by any block backend that reaches rt_blk_disk_probe_partition().

PoC Shape

Create a disk image with:

  1. A valid PMBR
  2. A valid primary GPT header
  3. A valid GPT entry array CRC
  4. At least one GPT partition entry satisfying:
    • partition_type_guid != NULL_GUID
    • starting_lba <= lastlba
    • ending_lba <= lastlba
    • ending_lba < starting_lba

For example:

starting_lba = 0x1000
ending_lba   = 0x0FFF

Both fields are inside disk bounds, but the end is before the start.

Expected Result

During partition probing:

  • is_pte_valid() accepts the entry
  • efi_partition() computes:
size = 0x0FFF - 0x1000 + 1

which underflows to a huge rt_uint64_t value.

  • blk_put_partition() registers a logical partition with that wrapped size.

Minimal Reproduction Steps

  1. Enable the new block partition probing path with EFI/GPT support.
  2. Supply the crafted GPT image through any disk backend.
  3. Trigger rt_blk_disk_probe_partition().
  4. Observe that the malformed partition is accepted and a partition with a huge wrapped size is created.

Impact

The immediate impact is that malformed GPT metadata can create an invalid logical partition with a huge sector count. This can break the partition abstraction and may enable later incorrect reads/writes, boundary confusion, or other follow-on faults in code that trusts the partition object's stored geometry.

So even though the trigger is a malformed GPT image, the root cause is a missing semantic validity check in the parser.


Upstream / Downstream Impact

Upstream

Verified on current master in the new block EFI/GPT parser implementation.

Downstream

Any downstream product based on current master that includes the new block partition subsystem and parses untrusted or externally supplied GPT media/images may be affected.


Suggested Fix

Reject GPT entries where the end LBA is before the start LBA:

rt_inline rt_bool_t is_pte_valid(const gpt_entry *pte, const rt_size_t lastlba)
{
    rt_uint64_t start = rt_le64_to_cpu(pte->starting_lba);
    rt_uint64_t end = rt_le64_to_cpu(pte->ending_lba);

    if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
        start > lastlba ||
        end > lastlba ||
        end < start)
    {
        return RT_FALSE;
    }

    return RT_TRUE;
}

Optionally, efi_partition() may also defensively re-check the relation before computing size = end - start + 1ULL, to avoid similar bugs if future validation changes.

Kindly let me know if you intend to request a CVE ID upon confirmation of the vulnerability.

Other additional context

No response

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions