ANDROID: mm: Fix page table lookup in speculative fault path

In speculative fault path, while doing page table lookup, offset
is obtained at each level and value at that offset is read and
checks are perfomed on it, later to get next level offset we read
from previous level offset again. A concurrent page table reclaimation
operation could result in change in value at this offset, and we go
ahead and access it, this would result in reading an invalid entry.
Fix this by reading from previous level offset again and comparing
before performing next level access.

Bug: 221005439
Change-Id: I66b3d24ae79c7ee5ccce4ba7a94f028f4cf3fda0
Signed-off-by: Vijayanand Jitta <quic_vjitta@quicinc.com>
This commit is contained in:
Vijayanand Jitta
2022-03-02 22:25:21 +05:30
committed by Suren Baghdasaryan
parent e53b1b9ad4
commit a817d6ed87

View File

@@ -5033,11 +5033,15 @@ static vm_fault_t ___handle_speculative_fault(struct mm_struct *mm,
goto out_walk;
p4d = p4d_offset(pgd, address);
if (pgd_val(READ_ONCE(*pgd)) != pgd_val(pgdval))
goto out_walk;
p4dval = READ_ONCE(*p4d);
if (p4d_none(p4dval) || unlikely(p4d_bad(p4dval)))
goto out_walk;
vmf.pud = pud_offset(p4d, address);
if (p4d_val(READ_ONCE(*p4d)) != p4d_val(p4dval))
goto out_walk;
pudval = READ_ONCE(*vmf.pud);
if (pud_none(pudval) || unlikely(pud_bad(pudval)))
goto out_walk;
@@ -5047,6 +5051,8 @@ static vm_fault_t ___handle_speculative_fault(struct mm_struct *mm,
goto out_walk;
vmf.pmd = pmd_offset(vmf.pud, address);
if (pud_val(READ_ONCE(*vmf.pud)) != pud_val(pudval))
goto out_walk;
vmf.orig_pmd = READ_ONCE(*vmf.pmd);
/*
* pmd_none could mean that a hugepage collapse is in progress
@@ -5074,6 +5080,11 @@ static vm_fault_t ___handle_speculative_fault(struct mm_struct *mm,
*/
vmf.pte = pte_offset_map(vmf.pmd, address);
if (pmd_val(READ_ONCE(*vmf.pmd)) != pmd_val(vmf.orig_pmd)) {
pte_unmap(vmf.pte);
vmf.pte = NULL;
goto out_walk;
}
vmf.orig_pte = READ_ONCE(*vmf.pte);
barrier(); /* See comment in handle_pte_fault() */
if (pte_none(vmf.orig_pte)) {