PT-2026-51863 · Linux · Linux

Published

2026-06-24

·

Updated

2026-06-24

·

CVE-2026-52969

None

No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
KVM: Reject wrapped offset in kvm reset dirty gfn()
kvm reset dirty gfn() guards the gfn range with
if (!memslot || (offset +  fls(mask)) >= memslot->npages)
	return;
but offset is u64 and the addition is unchecked. The check can be silently bypassed by a u64 wrap.
The dirty ring backing those entries is MAP SHARED at KVM DIRTY LOG PAGE OFFSET of the vcpu fd, so the VMM can rewrite the slot and offset fields of any entry between when the kernel pushes them and when KVM RESET DIRTY RINGS consumes them. On reset, kvm dirty ring reset() re-reads the values via READ ONCE() and feeds them straight back into this check; only the flags handshake is treated as the handover, the slot/offset payload is taken on trust.
Crafting two entries
entry[i].offset  = 0xffffffffffffffc1
entry[i+1].offset = 0
makes the coalescing loop in kvm dirty ring reset() compute
delta = (s64)(0 - 0xffffffffffffffc1) = 63
which falls in [0, BITS PER LONG), so it folds entry[i+1] into the existing mask by setting bit 63. The trailing kvm reset dirty gfn() call then sees offset = 0xffffffffffffffc1 and fls(mask) = 63; the sum is 0 in u64 and the bounds check passes.
That offset propagates into kvm arch mmu enable log dirty pt masked() unchanged. On the legacy MMU path -- kvm memslots have rmaps() == true, i.e. shadow paging, any VM that has allocated shadow roots, or a write-tracked slot -- it reaches gfn to rmap(), which indexes slot->arch.rmap[0][] with a near-U64 MAX gfn. That is an out-of-bounds load of a kvm rmap head, followed by a conditional clear of PT WRITABLE MASK in whatever the loaded pointer points at. The path is reachable from any process holding /dev/kvm.
Range-check offset on its own first, so the addition cannot wrap. memslot->npages is bounded well below U64 MAX, so once offset < npages holds, offset + fls(mask) (with fls(mask) < BITS PER LONG) stays in range.
Found an issue in the description? Have something to add? Feel free to write us 👾

Related Identifiers

CVE-2026-52969

Affected Products

Linux