From c3cbea92297d5605d88cf7f4fd48104421807341 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Wed, 17 Feb 2021 14:48:00 +0530 Subject: [PATCH] ANDROID: mm: avoid writing to read-only elements Refactor speculative page fault handler to avoid assigning to read-only elements of vmfault struct. Change-Id: I1b5072d880a485948fad9591d7e8dc20e47d73a4 Bug: 171278850 Signed-off-by: Vinayak Menon --- mm/memory.c | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 17938b021a24..7bdbafa70cd6 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -4775,12 +4775,15 @@ static inline void mm_account_fault(struct pt_regs *regs, * This is needed as the returned vma is kept in memory until the call to * can_reuse_spf_vma() is made. */ -vm_fault_t __handle_speculative_fault(struct mm_struct *mm, - unsigned long address, unsigned int flags, - struct vm_area_struct **vma) +static vm_fault_t ___handle_speculative_fault(struct mm_struct *mm, + unsigned long address, unsigned int flags, + struct vm_area_struct *vma) { struct vm_fault vmf = { .address = address, + .pgoff = linear_page_index(vma, address), + .vma = vma, + .gfp_mask = __get_fault_gfp_mask(vma), }; pgd_t *pgd, pgdval; p4d_t *p4d, p4dval; @@ -4792,13 +4795,6 @@ vm_fault_t __handle_speculative_fault(struct mm_struct *mm, flags &= ~(FAULT_FLAG_ALLOW_RETRY|FAULT_FLAG_KILLABLE); flags |= FAULT_FLAG_SPECULATIVE; - check_sync_rss_stat(current); - - *vma = get_vma(mm, address); - if (!*vma) - return VM_FAULT_RETRY; - vmf.vma = *vma; - /* rmb <-> seqlock,vma_rb_erase() */ seq = raw_read_seqcount(&vmf.vma->vm_sequence); if (seq & 1) { @@ -4939,8 +4935,6 @@ vm_fault_t __handle_speculative_fault(struct mm_struct *mm, vmf.pte = NULL; } - vmf.pgoff = linear_page_index(vmf.vma, address); - vmf.gfp_mask = __get_fault_gfp_mask(vmf.vma); vmf.sequence = seq; vmf.flags = flags; @@ -4959,14 +4953,8 @@ vm_fault_t __handle_speculative_fault(struct mm_struct *mm, ret = handle_pte_fault(&vmf); mem_cgroup_exit_user_fault(); - /* - * If there is no need to retry, don't return the vma to the caller. - */ - if (ret != VM_FAULT_RETRY) { + if (ret != VM_FAULT_RETRY) count_vm_event(SPECULATIVE_PGFAULT); - put_vma(vmf.vma); - *vma = NULL; - } /* * The task may have entered a memcg OOM situation but @@ -4985,15 +4973,34 @@ vm_fault_t __handle_speculative_fault(struct mm_struct *mm, out_segv: trace_spf_vma_access(_RET_IP_, vmf.vma, address); - /* - * We don't return VM_FAULT_RETRY so the caller is not expected to - * retrieve the fetched VMA. - */ - put_vma(vmf.vma); - *vma = NULL; return VM_FAULT_SIGSEGV; } +vm_fault_t __handle_speculative_fault(struct mm_struct *mm, + unsigned long address, unsigned int flags, + struct vm_area_struct **vma) +{ + vm_fault_t ret; + + check_sync_rss_stat(current); + + *vma = get_vma(mm, address); + if (!*vma) + return VM_FAULT_RETRY; + + ret = ___handle_speculative_fault(mm, address, flags, *vma); + + /* + * If there is no need to retry, don't return the vma to the caller. + */ + if (ret != VM_FAULT_RETRY) { + put_vma(*vma); + *vma = NULL; + } + + return ret; +} + /* * This is used to know if the vma fetch in the speculative page fault handler * is still valid when trying the regular fault path while holding the