{"id":"CVE-2024-46787","revision":"ecf32fa585cc43898f561d44748ea6f2","records":[{"revision":"ecf32fa585cc43898f561d44748ea6f2","observedAt":"2026-10-30T13:45:33.454+00:00","statement":{"source":"cve-program","id":"CVE-2024-46787","aliases":[],"title":"userfaultfd: fix checks for huge PMDs","description":"In the Linux kernel, the following vulnerability has been resolved:\n\nuserfaultfd: fix checks for huge PMDs\n\nPatch series \"userfaultfd: fix races around pmd_trans_huge() check\", v2.\n\nThe pmd_trans_huge() code in mfill_atomic() is wrong in three different\nways depending on kernel version:\n\n1. The pmd_trans_huge() check is racy and can lead to a BUG_ON() (if you hit\n   the right two race windows) - I've tested this in a kernel build with\n   some extra mdelay() calls. See the commit message for a description\n   of the race scenario.\n   On older kernels (before 6.5), I think the same bug can even\n   theoretically lead to accessing transhuge page contents as a page table\n   if you hit the right 5 narrow race windows (I haven't tested this case).\n2. As pointed out by Qi Zheng, pmd_trans_huge() is not sufficient for\n   detecting PMDs that don't point to page tables.\n   On older kernels (before 6.5), you'd just have to win a single fairly\n   wide race to hit this.\n   I've tested this on 6.1 stable by racing migration (with a mdelay()\n   patched into try_to_migrate()) against UFFDIO_ZEROPAGE - on my x86\n   VM, that causes a kernel oops in ptlock_ptr().\n3. On newer kernels (>=6.5), for shmem mappings, khugepaged is allowed\n   to yank page tables out from under us (though I haven't tested that),\n   so I think the BUG_ON() checks in mfill_atomic() are just wrong.\n\nI decided to write two separate fixes for these (one fix for bugs 1+2, one\nfix for bug 3), so that the first fix can be backported to kernels\naffected by bugs 1+2.\n\n\nThis patch (of 2):\n\nThis fixes two issues.\n\nI discovered that the following race can occur:\n\n  mfill_atomic                other thread\n  ============                ============\n                              <zap PMD>\n  pmdp_get_lockless() [reads none pmd]\n  <bail if trans_huge>\n  <if none:>\n                              <pagefault creates transhuge zeropage>\n    __pte_alloc [no-op]\n                              <zap PMD>\n  <bail if pmd_trans_huge(*dst_pmd)>\n  BUG_ON(pmd_none(*dst_pmd))\n\nI have experimentally verified this in a kernel with extra mdelay() calls;\nthe BUG_ON(pmd_none(*dst_pmd)) triggers.\n\nOn kernels newer than commit 0d940a9b270b (\"mm/pgtable: allow\npte_offset_map[_lock]() to fail\"), this can't lead to anything worse than\na BUG_ON(), since the page table access helpers are actually designed to\ndeal with page tables concurrently disappearing; but on older kernels\n(<=6.4), I think we could probably theoretically race past the two\nBUG_ON() checks and end up treating a hugepage as a page table.\n\nThe second issue is that, as Qi Zheng pointed out, there are other types\nof huge PMDs that pmd_trans_huge() can't catch: devmap PMDs and swap PMDs\n(in particular, migration PMDs).\n\nOn <=6.4, this is worse than the first issue: If mfill_atomic() runs on a\nPMD that contains a migration entry (which just requires winning a single,\nfairly wide race), it will pass the PMD to pte_offset_map_lock(), which\nassumes that the PMD points to a page table.\n\nBreakage follows: First, the kernel tries to take the PTE lock (which will\ncrash or maybe worse if there is no \"struct page\" for the address bits in\nthe migration entry PMD - I think at least on X86 there usually is no\ncorresponding \"struct page\" thanks to the PTE inversion mitigation, amd64\nlooks different).\n\nIf that didn't crash, the kernel would next try to write a PTE into what\nit wrongly thinks is a page table.\n\nAs part of fixing these issues, get rid of the check for pmd_trans_huge()\nbefore __pte_alloc() - that's redundant, we're going to have to check for\nthat after the __pte_alloc() anyway.\n\nBackport note: pmdp_get_lockless() is pmd_read_atomic() in older kernels.","state":0,"publishedAt":"2024-09-18T07:12:43.264+00:00","modifiedAt":"2026-10-30T12:19:19.182+00:00","affected":[{"ecosystem":"Vendor product","name":"Linux","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"product\": \"Linux\",\n                    \"vendor\": \"Linux\",\n                    \"defaultStatus\": \"unaffected\",\n                    \"repo\": \"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\n                    \"programFiles\": [\n                        \"mm/userfaultfd.c\"\n                    ],\n                    \"versions\": [\n                        {\n                            \"version\": \"c1a4de99fada21e2e9251e52cbb51eff5aadc757\",\n                            \"lessThan\": \"b25c0767a6a18a8399f57c63e50b5cc19037e90a\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"git\"\n                        },\n                        {\n                            \"version\": \"c1a4de99fada21e2e9251e52cbb51eff5aadc757\",\n                            \"lessThan\": \"3c6b4bcf37845c9359aed926324bed66bdd2448d\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"git\"\n                        },\n                        {\n                            \"version\": \"c1a4de99fada21e2e9251e52cbb51eff5aadc757\",\n                            \"lessThan\": \"98cc18b1b71e23fe81a5194ed432b20c2d81a01a\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"git\"\n                        },\n                        {\n                            \"version\": \"c1a4de99fada21e2e9251e52cbb51eff5aadc757\",\n                            \"lessThan\": \"71c186efc1b2cf1aeabfeff3b9bd5ac4c5ac14d8\",\n                            \"status\": \"affected\",\n                            \"versionType\": \"git\"\n                        }\n                    ]\n                }"},{"ecosystem":"Vendor product","name":"Linux","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"product\": \"Linux\",\n                    \"vendor\": \"Linux\",\n                    \"defaultStatus\": \"affected\",\n                    \"repo\": \"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\n                    \"programFiles\": [\n                        \"mm/userfaultfd.c\"\n                    ],\n                    \"versions\": [\n                        {\n                            \"version\": \"4.3\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \"0\",\n                            \"lessThan\": \"4.3\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        },\n                        {\n                            \"version\": \"6.1.191\",\n                            \"lessThanOrEqual\": \"6.1.*\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        },\n                        {\n                            \"version\": \"6.6.51\",\n                            \"lessThanOrEqual\": \"6.6.*\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        },\n                        {\n                            \"version\": \"6.10.10\",\n                            \"lessThanOrEqual\": \"6.10.*\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"semver\"\n                        },\n                        {\n                            \"version\": \"6.11\",\n                            \"lessThanOrEqual\": \"*\",\n                            \"status\": \"unaffected\",\n                            \"versionType\": \"original_commit_for_fix\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H","score":7.8,"severity":"HIGH"}],"references":["https://git.kernel.org/stable/c/b25c0767a6a18a8399f57c63e50b5cc19037e90a","https://git.kernel.org/stable/c/3c6b4bcf37845c9359aed926324bed66bdd2448d","https://git.kernel.org/stable/c/98cc18b1b71e23fe81a5194ed432b20c2d81a01a","https://git.kernel.org/stable/c/71c186efc1b2cf1aeabfeff3b9bd5ac4c5ac14d8"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2024-46787","license":"CVE Program Terms of Use","key":"cve-program:CVE-2024-46787","identifiers":["CVE-2024-46787"]},"retained":false,"historicalAffected":[]}],"coverage":[]}