CVE-2024-46787
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
18/09/2024
Last modified:
20/11/2024
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
userfaultfd: fix checks for huge PMDs<br />
<br />
Patch series "userfaultfd: fix races around pmd_trans_huge() check", v2.<br />
<br />
The pmd_trans_huge() code in mfill_atomic() is wrong in three different<br />
ways depending on kernel version:<br />
<br />
1. The pmd_trans_huge() check is racy and can lead to a BUG_ON() (if you hit<br />
the right two race windows) - I&#39;ve tested this in a kernel build with<br />
some extra mdelay() calls. See the commit message for a description<br />
of the race scenario.<br />
On older kernels (before 6.5), I think the same bug can even<br />
theoretically lead to accessing transhuge page contents as a page table<br />
if you hit the right 5 narrow race windows (I haven&#39;t tested this case).<br />
2. As pointed out by Qi Zheng, pmd_trans_huge() is not sufficient for<br />
detecting PMDs that don&#39;t point to page tables.<br />
On older kernels (before 6.5), you&#39;d just have to win a single fairly<br />
wide race to hit this.<br />
I&#39;ve tested this on 6.1 stable by racing migration (with a mdelay()<br />
patched into try_to_migrate()) against UFFDIO_ZEROPAGE - on my x86<br />
VM, that causes a kernel oops in ptlock_ptr().<br />
3. On newer kernels (>=6.5), for shmem mappings, khugepaged is allowed<br />
to yank page tables out from under us (though I haven&#39;t tested that),<br />
so I think the BUG_ON() checks in mfill_atomic() are just wrong.<br />
<br />
I decided to write two separate fixes for these (one fix for bugs 1+2, one<br />
fix for bug 3), so that the first fix can be backported to kernels<br />
affected by bugs 1+2.<br />
<br />
<br />
This patch (of 2):<br />
<br />
This fixes two issues.<br />
<br />
I discovered that the following race can occur:<br />
<br />
mfill_atomic other thread<br />
============ ============<br />
<br />
pmdp_get_lockless() [reads none pmd]<br />
<br />
<br />
<br />
__pte_alloc [no-op]<br />
<br />
<br />
BUG_ON(pmd_none(*dst_pmd))<br />
<br />
I have experimentally verified this in a kernel with extra mdelay() calls;<br />
the BUG_ON(pmd_none(*dst_pmd)) triggers.<br />
<br />
On kernels newer than commit 0d940a9b270b ("mm/pgtable: allow<br />
pte_offset_map[_lock]() to fail"), this can&#39;t lead to anything worse than<br />
a BUG_ON(), since the page table access helpers are actually designed to<br />
deal with page tables concurrently disappearing; but on older kernels<br />
(
Impact
Base Score 3.x
4.70
Severity 3.x
MEDIUM
Vulnerable products and versions
CPE | From | Up to |
---|---|---|
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 4.3 (including) | 6.6.51 (excluding) |
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* | 6.7 (including) | 6.10.10 (excluding) |
cpe:2.3:o:linux:linux_kernel:6.11:rc1:*:*:*:*:*:* | ||
cpe:2.3:o:linux:linux_kernel:6.11:rc2:*:*:*:*:*:* | ||
cpe:2.3:o:linux:linux_kernel:6.11:rc3:*:*:*:*:*:* | ||
cpe:2.3:o:linux:linux_kernel:6.11:rc4:*:*:*:*:*:* | ||
cpe:2.3:o:linux:linux_kernel:6.11:rc5:*:*:*:*:*:* | ||
cpe:2.3:o:linux:linux_kernel:6.11:rc6:*:*:*:*:*:* |
To consult the complete list of CPE names with products and versions, see this page