[PATCH] partitions/efi: reject GPT entries with starting_lba > ending_lba
From: Nguyen Le Thanh Tung
Date: Mon Jul 27 2026 - 00:08:01 EST
is_pte_valid() checks that both LBAs of a GPT partition entry are within
the device, but never that the entry describes a forward range:
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
le64_to_cpu(pte->starting_lba) > lastlba ||
le64_to_cpu(pte->ending_lba) > lastlba)
return 0;
EndingLBA is defined as the last LBA of the partition, so a conforming
entry always has StartingLBA <= EndingLBA. A crafted table can invert
the two while keeping both within the device, and efi_partition() then
computes the length as
u64 size = le64_to_cpu(ptes[i].ending_lba) -
le64_to_cpu(ptes[i].starting_lba) + 1ULL;
which underflows to a value close to U64_MAX.
The "extends beyond EOD" clamp in blk_add_partition() does not contain
this, because it tests
if (from + size > get_capacity(disk))
and from + size wraps for a size of that magnitude, so the sum comes out
small, the clamp is skipped and the partition is registered with the
underflowed length. From then on bio_check_eod() is evaluated against
bdev_nr_sectors() of that partition, i.e. against the bogus length, so
I/O submitted through the partition device is no longer confined to the
partition and reaches sectors owned by other partitions of the same
disk.
This was verified on 6.8.12 with a crafted two partition image: the
inverted entry is registered as a partition of nearly 2^64 sectors
with no "extends beyond EOD" warning, and BLKZEROOUT issued on
that partition overwrote known marker data belonging to the other,
unrelated partition on the same disk. No privileged step is
needed on the victim side beyond getting the table parsed, which happens
automatically for removable media on a typical desktop.
Reject the inverted range in is_pte_valid(), the single place every GPT
entry is gated on. The code has been this way since the beginning of
git history.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Nguyen Le Thanh Tung <nguyenlethanhtung555@xxxxxxxxx>
---
Compile tested on 6.8.12: `make W=1 block/partitions/efi.o` produces no
new warnings. The behaviour described above was reproduced on that same
kernel with a crafted image. is_pte_valid() is byte identical in 6.8,
current mainline and linux-next.
block/partitions/efi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/block/partitions/efi.c b/block/partitions/efi.c
index 9865d59..000219a 100644
--- a/block/partitions/efi.c
+++ b/block/partitions/efi.c
@@ -461,7 +461,8 @@ is_pte_valid(const gpt_entry *pte, const u64 lastlba)
{
if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
le64_to_cpu(pte->starting_lba) > lastlba ||
- le64_to_cpu(pte->ending_lba) > lastlba)
+ le64_to_cpu(pte->ending_lba) > lastlba ||
+ le64_to_cpu(pte->starting_lba) > le64_to_cpu(pte->ending_lba))
return 0;
return 1;
}
--
2.53.0