Repository navigation
[Bug] integer overflow in GPT entry allocation causes OOB read on 32-bit targets #11260
Description
RT-Thread Version
master (verified on commit 6a635e32d9f39ea015824927cee492620a05212f); also present in v5.2.2, v5.2.1, and v5.2.0
Hardware Type/Architectures
Any 32-bit BSP with GPT partition probing enabled (RT_BLK_PARTITION_EFI)
Develop Toolchain
Other
Describe the bug
This issue is independent from #11259, which reports a different bug in read_lba().
A 32-bit-only memory-safety issue exists in components/drivers/block/partitions/efi.c. The GPT parser computes the allocation size for the partition
entry array using rt_size_t, which is 32-bit on 32-bit builds, but later iterates over the entry array using the original untrusted on-disk entry count.
Affected code:
/* components/drivers/block/partitions/efi.c */
count = (rt_size_t)rt_le32_to_cpu(gpt->num_partition_entries) *
rt_le32_to_cpu(gpt->sizeof_partition_entry);
pte = rt_malloc(count);Later:
/* components/drivers/block/partitions/efi.c */
entries_nr = rt_le32_to_cpu(gpt->num_partition_entries);
for (int i = 0; i < entries_nr && i < disk->max_partitions; ++i)
{
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 (!is_pte_valid(&ptes[i], last_lba(disk)))
{
continue;
}
...
}
On 32-bit RT-Thread builds, rt_size_t is 32-bit:
/* include/rttypes.h */
#ifdef ARCH_CPU_64BIT
typedef rt_uint64_t rt_ubase_t;
#else
typedef rt_uint32_t rt_ubase_t;
#endif
...
typedef rt_ubase_t rt_size_t;
The code also later enforces:
rt_le32_to_cpu((*gpt)->sizeof_partition_entry) == sizeof(gpt_entry)
So the allocation is effectively based on:
num_partition_entries * 128
This multiplication can wrap on 32-bit targets and produce a much smaller non-zero allocation.
For example, with a crafted GPT header:
- num_partition_entries = 0x02000004
- sizeof_partition_entry = 128
the true product is 0x100000200, but the 32-bit wrapped allocation size becomes 0x200 (512 bytes), which only holds 4 GPT entries.
However, efi_partition() still trusts the original entries_nr = 0x02000004 and iterates until i < disk->max_partitions.
Many common MMC/SD block devices default to 16 partitions:
/* components/drivers/sdio/dev_block.c */
#ifndef RT_MMCSD_MAX_PARTITION
#define RT_MMCSD_MAX_PARTITION 16
#endif
...
blk_dev->parent.max_partitions = RT_MMCSD_MAX_PARTITION;
As a result, on a common 32-bit MMC/SD configuration, the parser may allocate space for only 4 entries but still read ptes[4] through ptes[15], causing an
out-of-bounds read from heap memory.
Steps to reproduce the behavior
- Build RT-Thread for a 32-bit target with GPT partition probing enabled.
- Present a crafted GPT disk image or block device to the system.
- Set sizeof_partition_entry = 128.
- Set num_partition_entries = 0x02000004.
- Trigger normal partition probing.
Expected behavior
The parser should reject GPT headers when:
- num_partition_entries * sizeof_partition_entry overflows
- the computed allocation size cannot represent the claimed number of entries
- later iteration would exceed the actually allocated entry count
Actual behavior
The allocation size wraps on 32-bit builds, but later code still indexes the GPT entry array using the original untrusted entry count, leading to out-of-
bounds reads and undefined behavior. Depending on heap layout and target configuration, this may cause crashes or cause heap data to be interpreted as fake
GPT entries.
Suggested fix
- Reject integer overflow before allocation. For example, validate:
entries_nr = rt_le32_to_cpu(gpt->num_partition_entries);
entry_size = rt_le32_to_cpu(gpt->sizeof_partition_entry);
if (entry_size != sizeof(gpt_entry) ||
entries_nr == 0 ||
entries_nr > RT_SIZE_MAX / entry_size)
{
return RT_NULL;
}
- Use the validated entry count consistently after allocation instead of reusing the raw on-disk value.
- Bound the later iteration by the number of entries actually allocated, for example:
validated_entries = count / sizeof(gpt_entry);
for (i = 0; i < validated_entries && i < disk->max_partitions; ++i)
- More generally, avoid recomputing lengths from untrusted GPT header fields after allocation unless the same overflow checks are applied again.
Kindly let me know if you intend to request a CVE ID upon confirmation of the vulnerability.
Other additional context
No response
Activity
GuEe-GUI commentedon Mar 17, 2026
There is the UEFI Specification (2.11) : https://uefi.org/specs/UEFI/2.11/05_GUID_Partition_Table_Format.html
The specification have some limits:
A minimum of 16,384 bytes of space must be reserved for the GPT Partition Entry Array.
The SizeOfPartitionEntry is 128 x 2^n, So the Maximum of NumberOfPartitionEntries should be: 16384 / 128 = 128
Anyway, the count will overflow never, don’t care.
XueDugu commentedon Mar 17, 2026
Thanks for checking.
I think the UEFI spec point is being interpreted incorrectly here.
The spec says a minimum of 16,384 bytes must be reserved for the GPT Partition Entry Array,
not a maximum. So with 128-byte entries,
16384 / 128 = 128is only the minimum number ofentries if the array uses exactly the minimum reserved space. It is not an upper bound on
NumberOfPartitionEntries.The same section defines:
NumberOfPartitionEntriesas a 32-bit header fieldNumberOfPartitionEntries * SizeOfPartitionEntryPartitionEntryLBA, with usable-space constraints viaFirstUsableLBASo larger arrays are still possible if more space is reserved before
FirstUsableLBA. Thespecification does not cap
NumberOfPartitionEntriesat 128.More importantly, the security issue here is about malformed on-disk metadata being processed
unsafely. RT-Thread currently does not validate that the claimed GPT entry array size is
representable in
rt_size_t, nor that it safely fits the later parser logic. In particular:On 32-bit targets, this multiplication can wrap to a much smaller non-zero allocation.
Later, the code computes:
But
efi_crc32()takesrt_size_t len, so on 32-bit targets the CRC length is truncated againto the wrapped size. That means a crafted GPT can still satisfy RT-Thread's CRC check using the
truncated byte length.
After that,
efi_partition()still uses the original on-disk count:So the actual issue is:
ptes[i]using the original untrustedentries_nr.So the concern is not "spec-compliant GPTs always use more than 128 entries". It is that
malformed attacker-controlled GPT metadata is not rejected safely, and the parser uses
inconsistent arithmetic widths in a memory-unsafe way on 32-bit targets.
If you prefer, I can update the issue description to reflect this more precisely.
Do I miss something important or misunderstand your idea?
GuEe-GUI commentedon Mar 17, 2026
OK. We should check the pt_size if the fucking attacker will do it like that:
The efi partition code is secure now.
XueDugu commentedon Mar 17, 2026
Thanks for confirming the vulnerability.
Do you intend to request/coordinate a CVE ID for this issue on behalf of RT-Thread?
If not, please let me know and I will proceed with a CVE request myself via the appropriate CNA / CNA-LR, referencing this issue and the fix once available.
GuEe-GUI commentedon Mar 17, 2026
Appreciate. We will fix it later without CVE.
[dm][block] fixup the EFI partition checked in 32bits
GuEe-GUI commentedon Mar 17, 2026
#11266
[dm][block] fixup the EFI partition checked in 32bits