From: Sasha Levin Date: Fri, 26 Feb 2021 19:15:14 +0000 (-0500) Subject: Fixes for 4.9 X-Git-Tag: v4.4.259~76^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=02ad79ec4186e63885bffa771f24663796544fd0;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 4.9 Signed-off-by: Sasha Levin --- diff --git a/queue-4.9/mm-thp-make-do_huge_pmd_wp_page-lock-page-for-testin.patch b/queue-4.9/mm-thp-make-do_huge_pmd_wp_page-lock-page-for-testin.patch new file mode 100644 index 00000000000..48251d5fca6 --- /dev/null +++ b/queue-4.9/mm-thp-make-do_huge_pmd_wp_page-lock-page-for-testin.patch @@ -0,0 +1,81 @@ +From 8c75a1994f358b2a08c425fa6084b13c14421409 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 26 Feb 2021 17:22:00 +0100 +Subject: mm, thp: make do_huge_pmd_wp_page() lock page for testing mapcount + +From: Vlastimil Babka + +Jann reported [1] a race between __split_huge_pmd_locked() and +page_trans_huge_map_swapcount() which can result in a page to be reused +instead of COWed. This was later assigned CVE-2020-29368. + +This was fixed by commit c444eb564fb1 ("mm: thp: make the THP mapcount atomic +against __split_huge_pmd_locked()") by doing the split under the page lock, +while all users of page_trans_huge_map_swapcount() were already also under page +lock. The fix was backported also to 4.9 stable series. + +When testing the backport on a 4.12 based kernel, Nicolai noticed the POC from +[1] still reproduces after backporting c444eb564fb1 and identified a missing +page lock in do_huge_pmd_wp_page() around the call to +page_trans_huge_mapcount(). The page lock was only added in ba3c4ce6def4 ("mm, +THP, swap: make reuse_swap_page() works for THP swapped out") in 4.14. The +commit also wrapped page_trans_huge_mapcount() into +page_trans_huge_map_swapcount() for the purposes of COW decisions. + +I have verified that 4.9.y indeed also reproduces with the POC. Backporting +ba3c4ce6def4 alone however is not possible as it's part of a larger effort of +optimizing THP swapping, which would be risky to backport fully. + +Therefore this 4.9-stable-only patch just wraps page_trans_huge_mapcount() +in page_trans_huge_mapcount() under page lock the same way as ba3c4ce6def4 +does, but without the page_trans_huge_map_swapcount() part. Other callers +of page_trans_huge_mapcount() are all under page lock already. I have verified +the POC no longer reproduces afterwards. + +[1] https://bugs.chromium.org/p/project-zero/issues/detail?id=2045 + +Reported-by: Nicolai Stange +Signed-off-by: Vlastimil Babka +Signed-off-by: Sasha Levin +--- + mm/huge_memory.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/mm/huge_memory.c b/mm/huge_memory.c +index 05ca01ef97f7f..14cd0ef33b628 100644 +--- a/mm/huge_memory.c ++++ b/mm/huge_memory.c +@@ -1022,6 +1022,19 @@ int do_huge_pmd_wp_page(struct fault_env *fe, pmd_t orig_pmd) + * We can only reuse the page if nobody else maps the huge page or it's + * part. + */ ++ if (!trylock_page(page)) { ++ get_page(page); ++ spin_unlock(fe->ptl); ++ lock_page(page); ++ spin_lock(fe->ptl); ++ if (unlikely(!pmd_same(*fe->pmd, orig_pmd))) { ++ unlock_page(page); ++ put_page(page); ++ goto out_unlock; ++ } ++ put_page(page); ++ } ++ + if (page_trans_huge_mapcount(page, NULL) == 1) { + pmd_t entry; + entry = pmd_mkyoung(orig_pmd); +@@ -1029,8 +1042,10 @@ int do_huge_pmd_wp_page(struct fault_env *fe, pmd_t orig_pmd) + if (pmdp_set_access_flags(vma, haddr, fe->pmd, entry, 1)) + update_mmu_cache_pmd(vma, fe->address, fe->pmd); + ret |= VM_FAULT_WRITE; ++ unlock_page(page); + goto out_unlock; + } ++ unlock_page(page); + get_page(page); + spin_unlock(fe->ptl); + alloc: +-- +2.27.0 + diff --git a/queue-4.9/series b/queue-4.9/series index 11988776728..d2e3371849d 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -6,3 +6,4 @@ arm64-tegra-add-power-domain-for-tegra210-hda.patch net-usb-qmi_wwan-adding-support-for-cinterion-mv31.patch cifs-set-cifs_mount_use_prefix_path-flag-on-setting-.patch scripts-recordmcount.pl-support-big-endian-for-arch-.patch +mm-thp-make-do_huge_pmd_wp_page-lock-page-for-testin.patch