-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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