{"id":"CVE-2026-52969","title":"In the Linux kernel, the following vulnerability has been resolved:\n\nKVM: Reject wrapped offset in kvm_reset_dirty_gfn()\n\nkvm_reset_dirty_gfn() guards the gfn range with\n\n\tif (!memslot || (offset + __fls(mask)) >= memslot->npages)\n\t\tretu…","summary":"In the Linux kernel, the following vulnerability has been resolved:\n\nKVM: Reject wrapped offset in kvm_reset_dirty_gfn()\n\nkvm_reset_dirty_gfn() guards the gfn range with\n\n\tif (!memslot || (offset + __fls(mask)) >= memslot->npages)\n\t\tretu…","severity":"high","cvss":7,"cvssVector":"CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H","cwe":["CWE-190"],"published":"2026-06-24","updated":"2026-07-10","source":"NVD","sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-52969","references":[{"url":"https://git.kernel.org/stable/c/01b71b930f15728aa8599478a7ce90c19dcd9fc2","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://git.kernel.org/stable/c/0d419c23bb11b5c9664de777c47c1f04a235882d","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://git.kernel.org/stable/c/0eb281eb95b2d4eea4db1da5fe91023aecc97095","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://git.kernel.org/stable/c/577a8d3bae0531f0e5ccfac919cd8192f920a804","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://git.kernel.org/stable/c/74f1a22f7a80f03d28ad8551a2d25d563433addf","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://git.kernel.org/stable/c/b315b033a877b1ee6d827810b5d7bb4392ffcf8d","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://git.kernel.org/stable/c/ecf9b3ea7847fe14f34b8c41f00de1eb95c747da","label":"416baaa9-dc9f-4396-8d5f-8c081fb06d67"},{"url":"https://access.redhat.com/security/cve/CVE-2026-52969","label":"0b0ca135-0b70-47e7-9f44-1890c2a1c46c"},{"url":"https://bugzilla.redhat.com/show_bug.cgi?id=2492434","label":"0b0ca135-0b70-47e7-9f44-1890c2a1c46c"},{"url":"https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-52969.json","label":"0b0ca135-0b70-47e7-9f44-1890c2a1c46c"}],"tags":["nvd"],"epss":0.00152,"epssPercentile":0.04748,"ingestedAt":"2026-07-11T13:13:25.068Z","slug":"CVE-2026-52969","body":"## Overview\n\nIn the Linux kernel, the following vulnerability has been resolved:\n\nKVM: Reject wrapped offset in kvm_reset_dirty_gfn()\n\nkvm_reset_dirty_gfn() guards the gfn range with\n\n\tif (!memslot || (offset + __fls(mask)) >= memslot->npages)\n\t\treturn;\n\nbut offset is u64 and the addition is unchecked.  The check can be\nsilently bypassed by a u64 wrap.\n\nThe dirty ring backing those entries is MAP_SHARED at\nKVM_DIRTY_LOG_PAGE_OFFSET of the vcpu fd, so the VMM can rewrite the\nslot and offset fields of any entry between when the kernel pushes\nthem and when KVM_RESET_DIRTY_RINGS consumes them.  On reset,\nkvm_dirty_ring_reset() re-reads the values via READ_ONCE() and feeds\nthem straight back into this check; only the flags handshake is\ntreated as the handover, the slot/offset payload is taken on trust.\n\nCrafting two entries\n\n\tentry[i].offset   = 0xffffffffffffffc1\n\tentry[i+1].offset = 0\n\nmakes the coalescing loop in kvm_dirty_ring_reset() compute\n\n\tdelta = (s64)(0 - 0xffffffffffffffc1) = 63\n\nwhich falls in [0, BITS_PER_LONG), so it folds entry[i+1] into the\nexisting mask by setting bit 63.  The trailing kvm_reset_dirty_gfn()\ncall then sees offset = 0xffffffffffffffc1 and __fls(mask) = 63;\nthe sum is 0 in u64 and the bounds check passes.\n\nThat offset propagates into kvm_arch_mmu_enable_log_dirty_pt_masked()\nunchanged.  On the legacy MMU path -- kvm_memslots_have_rmaps() ==\ntrue, i.e. shadow paging, any VM that has allocated shadow roots, or\na write-tracked slot -- it reaches gfn_to_rmap(), which indexes\nslot->arch.rmap[0][] with a near-U64_MAX gfn.  That is an\nout-of-bounds load of a kvm_rmap_head, followed by a conditional\nclear of PT_WRITABLE_MASK in whatever the loaded pointer points at.\nThe path is reachable from any process holding /dev/kvm.\n\nRange-check offset on its own first, so the addition cannot wrap.\nmemslot->npages is bounded well below U64_MAX, so once offset <\nnpages holds, offset + __fls(mask) (with __fls(mask) < BITS_PER_LONG)\nstays in range.\n\n## Remediation\n\nRefer to the linked advisories for vendor-supplied fixes and affected version ranges.","depth":"twilight","depthScore":39,"depthScoreParts":{"impact":38.5,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}