{"id":"CVE-2026-31456","state":"PUBLISHED","title":"mm/pagewalk: fix race between concurrent split and refault","description":"In the Linux kernel, the following vulnerability has been resolved:\n\nmm/pagewalk: fix race between concurrent split and refault\n\nThe splitting of a PUD entry in walk_pud_range() can race with a\nconcurrent thread refaulting the PUD leaf entry causing it to try walking\na PMD range that has disappeared.\n\nAn example and reproduction of this is to try reading numa_maps of a\nprocess while VFIO-PCI is setting up DMA (specifically the\nvfio_pin_pages_remote call) on a large BAR for that process.\n\nThis will trigger a kernel BUG:\nvfio-pci 0000:03:00.0: enabling device (0000 -> 0002)\nBUG: unable to handle page fault for address: ffffa23980000000\nPGD 0 P4D 0\nOops: Oops: 0000 [#1] SMP NOPTI\n...\nRIP: 0010:walk_pgd_range+0x3b5/0x7a0\nCode: 8d 43 ff 48 89 44 24 28 4d 89 ce 4d 8d a7 00 00 20 00 48 8b 4c 24\n28 49 81 e4 00 00 e0 ff 49 8d 44 24 ff 48 39 c8 4c 0f 43 e3 <49> f7 06\n   9f ff ff ff 75 3b 48 8b 44 24 20 48 8b 40 28 48 85 c0 74\nRSP: 0018:ffffac23e1ecf808 EFLAGS: 00010287\nRAX: 00007f44c01fffff RBX: 00007f4500000000 RCX: 00007f44ffffffff\nRDX: 0000000000000000 RSI: 000ffffffffff000 RDI: ffffffff93378fe0\nRBP: ffffac23e1ecf918 R08: 0000000000000004 R09: ffffa23980000000\nR10: 0000000000000020 R11: 0000000000000004 R12: 00007f44c0200000\nR13: 00007f44c0000000 R14: ffffa23980000000 R15: 00007f44c0000000\nFS:  00007fe884739580(0000) GS:ffff9b7d7a9c0000(0000)\nknlGS:0000000000000000\nCS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033\nCR2: ffffa23980000000 CR3: 000000c0650e2005 CR4: 0000000000770ef0\nPKRU: 55555554\nCall Trace:\n <TASK>\n __walk_page_range+0x195/0x1b0\n walk_page_vma+0x62/0xc0\n show_numa_map+0x12b/0x3b0\n seq_read_iter+0x297/0x440\n seq_read+0x11d/0x140\n vfs_read+0xc2/0x340\n ksys_read+0x5f/0xe0\n do_syscall_64+0x68/0x130\n ? get_page_from_freelist+0x5c2/0x17e0\n ? mas_store_prealloc+0x17e/0x360\n ? vma_set_page_prot+0x4c/0xa0\n ? __alloc_pages_noprof+0x14e/0x2d0\n ? __mod_memcg_lruvec_state+0x8d/0x140\n ? __lruvec_stat_mod_folio+0x76/0xb0\n ? __folio_mod_stat+0x26/0x80\n ? do_anonymous_page+0x705/0x900\n ? __handle_mm_fault+0xa8d/0x1000\n ? __count_memcg_events+0x53/0xf0\n ? handle_mm_fault+0xa5/0x360\n ? do_user_addr_fault+0x342/0x640\n ? arch_exit_to_user_mode_prepare.constprop.0+0x16/0xa0\n ? irqentry_exit_to_user_mode+0x24/0x100\n entry_SYSCALL_64_after_hwframe+0x76/0x7e\nRIP: 0033:0x7fe88464f47e\nCode: c0 e9 b6 fe ff ff 50 48 8d 3d be 07 0b 00 e8 69 01 02 00 66 0f 1f\n84 00 00 00 00 00 64 8b 04 25 18 00 00 00 85 c0 75 14 0f 05 <48> 3d 00\n   f0 ff ff 77 5a c3 66 0f 1f 84 00 00 00 00 00 48 83 ec 28\nRSP: 002b:00007ffe6cd9a9b8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000\nRAX: ffffffffffffffda RBX: 0000000000020000 RCX: 00007fe88464f47e\nRDX: 0000000000020000 RSI: 00007fe884543000 RDI: 0000000000000003\nRBP: 00007fe884543000 R08: 00007fe884542010 R09: 0000000000000000\nR10: fffffffffffffbc5 R11: 0000000000000246 R12: 0000000000000000\nR13: 0000000000000003 R14: 0000000000020000 R15: 0000000000020000\n </TASK>\n\nFix this by validating the PUD entry in walk_pmd_range() using a stable\nsnapshot (pudp_get()).  If the PUD is not present or is a leaf, retry the\nwalk via ACTION_AGAIN instead of descending further.  This mirrors the\nretry logic in walk_pte_range(), which lets walk_pmd_range() retry if the\nPTE is not being got by pte_offset_map_lock().","publishedAt":"2026-04-22T13:53:49.568Z","updatedAt":"2026-06-17T13:44:31.920Z","severity":null,"assigner":"Linux","products":["Linux Linux"],"affected":[{"vendor":"Linux","product":"Linux","defaultStatus":"unaffected","versions":[{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"138ada1337b47cc5efb08e517674d46f86268274","versionType":"git"},{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"38ec58670a0c5fc1edabdeccd857e586b7b3f318","versionType":"git"},{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"9bbbebd94dd5be25ec8c899d46ef01b33d5d22c0","versionType":"git"},{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"3b89863c3fa482912911cd65a12a3aeef662c250","versionType":"git"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["mm/pagewalk.c"]},{"vendor":"Linux","product":"Linux","defaultStatus":"affected","versions":[{"version":"6.12","status":"affected"},{"version":"0","status":"unaffected","lessThan":"6.12","versionType":"semver"},{"version":"6.12.84","status":"unaffected","lessThanOrEqual":"6.12.*","versionType":"semver"},{"version":"6.18.21","status":"unaffected","lessThanOrEqual":"6.18.*","versionType":"semver"},{"version":"6.19.11","status":"unaffected","lessThanOrEqual":"6.19.*","versionType":"semver"},{"version":"7.0","status":"unaffected","lessThanOrEqual":"*","versionType":"original_commit_for_fix"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["mm/pagewalk.c"]}],"references":["https://git.kernel.org/stable/c/138ada1337b47cc5efb08e517674d46f86268274","https://git.kernel.org/stable/c/38ec58670a0c5fc1edabdeccd857e586b7b3f318","https://git.kernel.org/stable/c/9bbbebd94dd5be25ec8c899d46ef01b33d5d22c0","https://git.kernel.org/stable/c/3b89863c3fa482912911cd65a12a3aeef662c250"],"weaknesses":[],"ingestedAt":"2026-10-29T20:11:40.391Z","source":{"repository":"CVEProject/cvelistV5","path":"cves/2026/31xxx/CVE-2026-31456.json","commit":"556c9d3a8cd17e218bb8e452ba7cd619a384ff47"},"raw":{"dataType":"CVE_RECORD","dataVersion":"5.2","cveMetadata":{"cveId":"CVE-2026-31456","state":"PUBLISHED","datePublished":"2026-04-22T13:53:49.568Z","dateUpdated":"2026-06-17T13:44:31.920Z","assignerShortName":"Linux","assignerOrgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","dateReserved":"2026-03-09T15:48:24.092Z"},"containers":{"cna":{"title":"mm/pagewalk: fix race between concurrent split and refault","descriptions":[{"lang":"en","value":"In the Linux kernel, the following vulnerability has been resolved:\n\nmm/pagewalk: fix race between concurrent split and refault\n\nThe splitting of a PUD entry in walk_pud_range() can race with a\nconcurrent thread refaulting the PUD leaf entry causing it to try walking\na PMD range that has disappeared.\n\nAn example and reproduction of this is to try reading numa_maps of a\nprocess while VFIO-PCI is setting up DMA (specifically the\nvfio_pin_pages_remote call) on a large BAR for that process.\n\nThis will trigger a kernel BUG:\nvfio-pci 0000:03:00.0: enabling device (0000 -> 0002)\nBUG: unable to handle page fault for address: ffffa23980000000\nPGD 0 P4D 0\nOops: Oops: 0000 [#1] SMP NOPTI\n...\nRIP: 0010:walk_pgd_range+0x3b5/0x7a0\nCode: 8d 43 ff 48 89 44 24 28 4d 89 ce 4d 8d a7 00 00 20 00 48 8b 4c 24\n28 49 81 e4 00 00 e0 ff 49 8d 44 24 ff 48 39 c8 4c 0f 43 e3 <49> f7 06\n   9f ff ff ff 75 3b 48 8b 44 24 20 48 8b 40 28 48 85 c0 74\nRSP: 0018:ffffac23e1ecf808 EFLAGS: 00010287\nRAX: 00007f44c01fffff RBX: 00007f4500000000 RCX: 00007f44ffffffff\nRDX: 0000000000000000 RSI: 000ffffffffff000 RDI: ffffffff93378fe0\nRBP: ffffac23e1ecf918 R08: 0000000000000004 R09: ffffa23980000000\nR10: 0000000000000020 R11: 0000000000000004 R12: 00007f44c0200000\nR13: 00007f44c0000000 R14: ffffa23980000000 R15: 00007f44c0000000\nFS:  00007fe884739580(0000) GS:ffff9b7d7a9c0000(0000)\nknlGS:0000000000000000\nCS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033\nCR2: ffffa23980000000 CR3: 000000c0650e2005 CR4: 0000000000770ef0\nPKRU: 55555554\nCall Trace:\n <TASK>\n __walk_page_range+0x195/0x1b0\n walk_page_vma+0x62/0xc0\n show_numa_map+0x12b/0x3b0\n seq_read_iter+0x297/0x440\n seq_read+0x11d/0x140\n vfs_read+0xc2/0x340\n ksys_read+0x5f/0xe0\n do_syscall_64+0x68/0x130\n ? get_page_from_freelist+0x5c2/0x17e0\n ? mas_store_prealloc+0x17e/0x360\n ? vma_set_page_prot+0x4c/0xa0\n ? __alloc_pages_noprof+0x14e/0x2d0\n ? __mod_memcg_lruvec_state+0x8d/0x140\n ? __lruvec_stat_mod_folio+0x76/0xb0\n ? __folio_mod_stat+0x26/0x80\n ? do_anonymous_page+0x705/0x900\n ? __handle_mm_fault+0xa8d/0x1000\n ? __count_memcg_events+0x53/0xf0\n ? handle_mm_fault+0xa5/0x360\n ? do_user_addr_fault+0x342/0x640\n ? arch_exit_to_user_mode_prepare.constprop.0+0x16/0xa0\n ? irqentry_exit_to_user_mode+0x24/0x100\n entry_SYSCALL_64_after_hwframe+0x76/0x7e\nRIP: 0033:0x7fe88464f47e\nCode: c0 e9 b6 fe ff ff 50 48 8d 3d be 07 0b 00 e8 69 01 02 00 66 0f 1f\n84 00 00 00 00 00 64 8b 04 25 18 00 00 00 85 c0 75 14 0f 05 <48> 3d 00\n   f0 ff ff 77 5a c3 66 0f 1f 84 00 00 00 00 00 48 83 ec 28\nRSP: 002b:00007ffe6cd9a9b8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000\nRAX: ffffffffffffffda RBX: 0000000000020000 RCX: 00007fe88464f47e\nRDX: 0000000000020000 RSI: 00007fe884543000 RDI: 0000000000000003\nRBP: 00007fe884543000 R08: 00007fe884542010 R09: 0000000000000000\nR10: fffffffffffffbc5 R11: 0000000000000246 R12: 0000000000000000\nR13: 0000000000000003 R14: 0000000000020000 R15: 0000000000020000\n </TASK>\n\nFix this by validating the PUD entry in walk_pmd_range() using a stable\nsnapshot (pudp_get()).  If the PUD is not present or is a leaf, retry the\nwalk via ACTION_AGAIN instead of descending further.  This mirrors the\nretry logic in walk_pte_range(), which lets walk_pmd_range() retry if the\nPTE is not being got by pte_offset_map_lock()."}],"affected":[{"vendor":"Linux","product":"Linux","defaultStatus":"unaffected","versions":[{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"138ada1337b47cc5efb08e517674d46f86268274","versionType":"git"},{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"38ec58670a0c5fc1edabdeccd857e586b7b3f318","versionType":"git"},{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"9bbbebd94dd5be25ec8c899d46ef01b33d5d22c0","versionType":"git"},{"version":"f9e54c3a2f5b79ecc57c7bc7d0d3521e461a2101","status":"affected","lessThan":"3b89863c3fa482912911cd65a12a3aeef662c250","versionType":"git"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["mm/pagewalk.c"]},{"vendor":"Linux","product":"Linux","defaultStatus":"affected","versions":[{"version":"6.12","status":"affected"},{"version":"0","status":"unaffected","lessThan":"6.12","versionType":"semver"},{"version":"6.12.84","status":"unaffected","lessThanOrEqual":"6.12.*","versionType":"semver"},{"version":"6.18.21","status":"unaffected","lessThanOrEqual":"6.18.*","versionType":"semver"},{"version":"6.19.11","status":"unaffected","lessThanOrEqual":"6.19.*","versionType":"semver"},{"version":"7.0","status":"unaffected","lessThanOrEqual":"*","versionType":"original_commit_for_fix"}],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","programFiles":["mm/pagewalk.c"]}],"references":[{"url":"https://git.kernel.org/stable/c/138ada1337b47cc5efb08e517674d46f86268274"},{"url":"https://git.kernel.org/stable/c/38ec58670a0c5fc1edabdeccd857e586b7b3f318"},{"url":"https://git.kernel.org/stable/c/9bbbebd94dd5be25ec8c899d46ef01b33d5d22c0"},{"url":"https://git.kernel.org/stable/c/3b89863c3fa482912911cd65a12a3aeef662c250"}],"providerMetadata":{"shortName":"Linux","orgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","dateUpdated":"2026-06-17T13:44:31.920Z"},"cpeApplicability":[{"nodes":[{"operator":"OR","negate":false,"cpeMatch":[{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"6.12","versionEndExcluding":"6.12.84"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"6.12","versionEndExcluding":"6.18.21"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"6.12","versionEndExcluding":"6.19.11"},{"vulnerable":true,"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionStartIncluding":"6.12","versionEndExcluding":"7.0"}]}]}],"x_generator":{"engine":"bippy-1.2.0"}}}}}