From 102a0743326a03cd1a1202ceda21e175b7d3575c Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Tue, 20 Feb 2024 01:20:52 +0000
Subject: [PATCH] add new system file

---
 kernel/mm/memory.c |   38 ++++++++++++++++++++++++++------------
 1 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/kernel/mm/memory.c b/kernel/mm/memory.c
index 834078a..857cfc9 100644
--- a/kernel/mm/memory.c
+++ b/kernel/mm/memory.c
@@ -246,6 +246,16 @@
 			   unsigned long addr)
 {
 	pgtable_t token = pmd_pgtable(*pmd);
+#ifdef CONFIG_SPECULATIVE_PAGE_FAULT
+	/*
+	 * Ensure page table destruction is blocked if __pte_map_lock managed
+	 * to take this lock. Without this barrier tlb_remove_table_rcu can
+	 * destroy ptl after __pte_map_lock locked it and during unlock would
+	 * cause a use-after-free.
+	 */
+	spinlock_t *ptl = pmd_lock(tlb->mm, pmd);
+	spin_unlock(ptl);
+#endif
 	pmd_clear(pmd);
 	pte_free_tlb(tlb, token, addr);
 	mm_dec_nr_ptes(tlb->mm);
@@ -2627,9 +2637,7 @@
 static bool pte_spinlock(struct vm_fault *vmf)
 {
 	bool ret = false;
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	pmd_t pmdval;
-#endif
 
 	/* Check if vma is still valid */
 	if (!(vmf->flags & FAULT_FLAG_SPECULATIVE)) {
@@ -2644,24 +2652,28 @@
 		goto out;
 	}
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	/*
 	 * We check if the pmd value is still the same to ensure that there
 	 * is not a huge collapse operation in progress in our back.
+	 * It also ensures that pmd was not cleared by pmd_clear in
+	 * free_pte_range and ptl is still valid.
 	 */
 	pmdval = READ_ONCE(*vmf->pmd);
 	if (!pmd_same(pmdval, vmf->orig_pmd)) {
 		trace_spf_pmd_changed(_RET_IP_, vmf->vma, vmf->address);
 		goto out;
 	}
-#endif
 
-	vmf->ptl = pte_lockptr(vmf->vma->vm_mm, vmf->pmd);
+	vmf->ptl = pte_lockptr(vmf->vma->vm_mm, &pmdval);
 	if (unlikely(!spin_trylock(vmf->ptl))) {
 		trace_spf_pte_lock(_RET_IP_, vmf->vma, vmf->address);
 		goto out;
 	}
 
+	/*
+	 * The check below will fail if pte_spinlock passed its ptl barrier
+	 * before we took the ptl lock.
+	 */
 	if (vma_has_changed(vmf)) {
 		spin_unlock(vmf->ptl);
 		trace_spf_vma_changed(_RET_IP_, vmf->vma, vmf->address);
@@ -2679,9 +2691,7 @@
 	bool ret = false;
 	pte_t *pte;
 	spinlock_t *ptl;
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	pmd_t pmdval;
-#endif
 
 	/*
 	 * The first vma_has_changed() guarantees the page-tables are still
@@ -2696,7 +2706,6 @@
 		goto out;
 	}
 
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
 	/*
 	 * We check if the pmd value is still the same to ensure that there
 	 * is not a huge collapse operation in progress in our back.
@@ -2706,7 +2715,6 @@
 		trace_spf_pmd_changed(_RET_IP_, vmf->vma, addr);
 		goto out;
 	}
-#endif
 
 	/*
 	 * Same as pte_offset_map_lock() except that we call
@@ -2715,14 +2723,18 @@
 	 * to invalidate TLB but this CPU has irq disabled.
 	 * Since we are in a speculative patch, accept it could fail
 	 */
-	ptl = pte_lockptr(vmf->vma->vm_mm, vmf->pmd);
-	pte = pte_offset_map(vmf->pmd, addr);
+	ptl = pte_lockptr(vmf->vma->vm_mm, &pmdval);
+	pte = pte_offset_map(&pmdval, addr);
 	if (unlikely(!spin_trylock(ptl))) {
 		pte_unmap(pte);
 		trace_spf_pte_lock(_RET_IP_, vmf->vma, addr);
 		goto out;
 	}
 
+	/*
+	 * The check below will fail if __pte_map_lock_speculative passed its ptl
+	 * barrier before we took the ptl lock.
+	 */
 	if (vma_has_changed(vmf)) {
 		pte_unmap_unlock(pte, ptl);
 		trace_spf_vma_changed(_RET_IP_, vmf->vma, addr);
@@ -3651,8 +3663,10 @@
 
 	if (!page) {
 		struct swap_info_struct *si = swp_swap_info(entry);
+		bool skip_swapcache = false;
 
-		if (data_race(si->flags & SWP_SYNCHRONOUS_IO) &&
+		trace_android_vh_skip_swapcache(entry, &skip_swapcache);
+		if ((data_race(si->flags & SWP_SYNCHRONOUS_IO) || skip_swapcache) &&
 		    __swap_count(entry) == 1) {
 			/* skip swapcache */
 			gfp_t flags = GFP_HIGHUSER_MOVABLE;

--
Gitblit v1.6.2