[Bug] integer overflow in GPT entry allocation causes OOB read on 32-bit targets
I maintainer di solito rispondono entro 1 giorno
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 45/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Ferma
- Stack tecnologico
- c
- Ambito
- embedded-iot, security
Direzione di ricerca
Inizia da components/drivers/block/partitions/efi.c, quindi esamina rt_size_t in include/rttypes.h e la configurazione di max_partitions in components/drivers/sdio/dev_block.c. Verifica il probing GPT su un target a 32 bit con l’header predisposto descritto; il lavoro è completato quando overflow viene rifiutato e l’iterazione non può superare il numero di voci GPT allocate.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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
- Lingua principale
- C
- Stelle
- 12.3k
- Fork
- 5.5k
- Merge medio
- 3g 8h
- PR unite (30g)
- 27
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di RT-Thread/rt-thread
-
[Bug] [netdev] ping crashes the shell with a division by zero when the target is unreachable (received == 0)Forse già presa @r3wretrhy l’ha presa 3 giorni fa. Apertabug Component component: net
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
RT-Thread/rt-thread#11852 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
[bsp][stm32][bluepill] README「快速上手」缺少重新生成 MDK 工程这一步,按文档操作无法编译通过Forse già presa @moment-NEW l’ha presa 6 giorni fa. Apertain progress
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
RT-Thread/rt-thread#11818 · 4 commenti · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
-
BSP BSP: Loongson bug RT-Smart
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
RT-Thread/rt-thread#11717 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Arch: RISC-V BSP BSP: HPMicro bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
RT-Thread/rt-thread#11687 · 3 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
RT-Thread/rt-thread#11472 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di RT-Thread/rt-thread
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
OpenPrinting/cups#1751 ·
I maintainer di solito rispondono entro 1 giorno
-
Warps 4 unit tests (raalloc)Apertaenhancement good first issue
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
Policy query leaks host primary block (BSL_PrimaryBlock_deinit skipped) on two early-exit pathsAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
NASA-AMMOS/BSL#355 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
arancormonk/dsd-neo#660 ·
I maintainer di solito rispondono entro 1 giorno