| From bippy-5f407fcff5a0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2024-50066: mm/mremap: fix move_normal_pmd/retract_page_tables race |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| mm/mremap: fix move_normal_pmd/retract_page_tables race |
| |
| In mremap(), move_page_tables() looks at the type of the PMD entry and the |
| specified address range to figure out by which method the next chunk of |
| page table entries should be moved. |
| |
| At that point, the mmap_lock is held in write mode, but no rmap locks are |
| held yet. For PMD entries that point to page tables and are fully covered |
| by the source address range, move_pgt_entry(NORMAL_PMD, ...) is called, |
| which first takes rmap locks, then does move_normal_pmd(). |
| move_normal_pmd() takes the necessary page table locks at source and |
| destination, then moves an entire page table from the source to the |
| destination. |
| |
| The problem is: The rmap locks, which protect against concurrent page |
| table removal by retract_page_tables() in the THP code, are only taken |
| after the PMD entry has been read and it has been decided how to move it. |
| So we can race as follows (with two processes that have mappings of the |
| same tmpfs file that is stored on a tmpfs mount with huge=advise); note |
| that process A accesses page tables through the MM while process B does it |
| through the file rmap: |
| |
| process A process B |
| ========= ========= |
| mremap |
| mremap_to |
| move_vma |
| move_page_tables |
| get_old_pmd |
| alloc_new_pmd |
| *** PREEMPT *** |
| madvise(MADV_COLLAPSE) |
| do_madvise |
| madvise_walk_vmas |
| madvise_vma_behavior |
| madvise_collapse |
| hpage_collapse_scan_file |
| collapse_file |
| retract_page_tables |
| i_mmap_lock_read(mapping) |
| pmdp_collapse_flush |
| i_mmap_unlock_read(mapping) |
| move_pgt_entry(NORMAL_PMD, ...) |
| take_rmap_locks |
| move_normal_pmd |
| drop_rmap_locks |
| |
| When this happens, move_normal_pmd() can end up creating bogus PMD entries |
| in the line `pmd_populate(mm, new_pmd, pmd_pgtable(pmd))`. The effect |
| depends on arch-specific and machine-specific details; on x86, you can end |
| up with physical page 0 mapped as a page table, which is likely |
| exploitable for user->kernel privilege escalation. |
| |
| Fix the race by letting process B recheck that the PMD still points to a |
| page table after the rmap locks have been taken. Otherwise, we bail and |
| let the caller fall back to the PTE-level copying path, which will then |
| bail immediately at the pmd_none() check. |
| |
| Bug reachability: Reaching this bug requires that you can create |
| shmem/file THP mappings - anonymous THP uses different code that doesn't |
| zap stuff under rmap locks. File THP is gated on an experimental config |
| flag (CONFIG_READ_ONLY_THP_FOR_FS), so on normal distro kernels you need |
| shmem THP to hit this bug. As far as I know, getting shmem THP normally |
| requires that you can mount your own tmpfs with the right mount flags, |
| which would require creating your own user+mount namespace; though I don't |
| know if some distros maybe enable shmem THP by default or something like |
| that. |
| |
| Bug impact: This issue can likely be used for user->kernel privilege |
| escalation when it is reachable. |
| |
| The Linux kernel CVE team has assigned CVE-2024-50066 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 6.6 with commit 1d65b771bc08cd054cf6d3766a72e113dc46d62f and fixed in 6.6.58 with commit 17396e32f975130b3e6251f024c8807d192e4c3e |
| Issue introduced in 6.6 with commit 1d65b771bc08cd054cf6d3766a72e113dc46d62f and fixed in 6.11.5 with commit 1552ce9ce8af47c0fe911682e5e1855e25851ca9 |
| Issue introduced in 6.6 with commit 1d65b771bc08cd054cf6d3766a72e113dc46d62f and fixed in 6.12 with commit 6fa1066fc5d00cb9f1b0e83b7ff6ef98d26ba2aa |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2024-50066 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| mm/mremap.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/17396e32f975130b3e6251f024c8807d192e4c3e |
| https://git.kernel.org/stable/c/1552ce9ce8af47c0fe911682e5e1855e25851ca9 |
| https://git.kernel.org/stable/c/6fa1066fc5d00cb9f1b0e83b7ff6ef98d26ba2aa |
| https://project-zero.issues.chromium.org/issues/371047675 |