cvelist/2024/46xxx/CVE-2024-46787.json

113 lines
8.5 KiB
JSON
Raw Normal View History

2024-09-11 16:01:06 +00:00
{
2024-09-18 08:00:37 +00:00
"data_version": "4.0",
2024-09-11 16:01:06 +00:00
"data_type": "CVE",
"data_format": "MITRE",
"CVE_data_meta": {
"ID": "CVE-2024-46787",
2024-09-18 08:00:37 +00:00
"ASSIGNER": "cve@kernel.org",
"STATE": "PUBLIC"
2024-09-11 16:01:06 +00:00
},
"description": {
"description_data": [
{
"lang": "eng",
2024-09-18 08:00:37 +00:00
"value": "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."
}
]
},
"problemtype": {
"problemtype_data": [
{
"description": [
{
"lang": "eng",
"value": "n/a"
}
]
}
]
},
"affects": {
"vendor": {
"vendor_data": [
{
"vendor_name": "Linux",
"product": {
"product_data": [
{
"product_name": "Linux",
"version": {
"version_data": [
{
"version_affected": "<",
"version_name": "c1a4de99fada",
"version_value": "3c6b4bcf3784"
},
{
"version_value": "not down converted",
"x_cve_json_5_version_data": {
"versions": [
{
"version": "4.3",
"status": "affected"
},
{
"version": "0",
"lessThan": "4.3",
"status": "unaffected",
2024-11-05 11:00:58 +00:00
"versionType": "semver"
2024-09-18 08:00:37 +00:00
},
{
"version": "6.6.51",
"lessThanOrEqual": "6.6.*",
"status": "unaffected",
2024-11-05 11:00:58 +00:00
"versionType": "semver"
2024-09-18 08:00:37 +00:00
},
{
"version": "6.10.10",
"lessThanOrEqual": "6.10.*",
"status": "unaffected",
2024-11-05 11:00:58 +00:00
"versionType": "semver"
2024-09-18 08:00:37 +00:00
},
{
"version": "6.11",
"lessThanOrEqual": "*",
"status": "unaffected",
"versionType": "original_commit_for_fix"
}
],
"defaultStatus": "affected"
}
}
]
}
}
]
}
}
]
}
},
"references": {
"reference_data": [
{
"url": "https://git.kernel.org/stable/c/3c6b4bcf37845c9359aed926324bed66bdd2448d",
"refsource": "MISC",
"name": "https://git.kernel.org/stable/c/3c6b4bcf37845c9359aed926324bed66bdd2448d"
},
{
"url": "https://git.kernel.org/stable/c/98cc18b1b71e23fe81a5194ed432b20c2d81a01a",
"refsource": "MISC",
"name": "https://git.kernel.org/stable/c/98cc18b1b71e23fe81a5194ed432b20c2d81a01a"
},
{
"url": "https://git.kernel.org/stable/c/71c186efc1b2cf1aeabfeff3b9bd5ac4c5ac14d8",
"refsource": "MISC",
"name": "https://git.kernel.org/stable/c/71c186efc1b2cf1aeabfeff3b9bd5ac4c5ac14d8"
2024-09-11 16:01:06 +00:00
}
]
2024-09-18 08:00:37 +00:00
},
"generator": {
2024-11-05 11:00:58 +00:00
"engine": "bippy-9e1c9544281a"
2024-09-11 16:01:06 +00:00
}
}