diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index f644d881ae51..89ccde9b2d3b 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -1227,6 +1227,7 @@ void do_user_addr_fault(struct pt_regs *regs, vm_fault_t fault; unsigned int flags = FAULT_FLAG_DEFAULT; #ifdef CONFIG_SPECULATIVE_PAGE_FAULT + struct vm_area_struct *orig_vma = NULL; struct vm_area_struct pvma; unsigned long seq; #endif @@ -1353,17 +1354,29 @@ void do_user_addr_fault(struct pt_regs *regs, count_vm_spf_event(SPF_ABORT_NO_SPECULATE); goto spf_abort; } + if (vma->vm_file) { + if (!vma_get_file_ref(vma)) { + rcu_read_unlock(); + count_vm_spf_event(SPF_ABORT_UNMAPPED); + goto spf_abort; + } + orig_vma = vma; + } pvma = *vma; rcu_read_unlock(); - if (!mmap_seq_read_check(mm, seq, SPF_ABORT_VMA_COPY)) + if (!mmap_seq_read_check(mm, seq, SPF_ABORT_VMA_COPY)) { + vma_put_file_ref(orig_vma); goto spf_abort; + } vma = &pvma; if (unlikely(access_error(error_code, vma))) { count_vm_spf_event(SPF_ABORT_ACCESS_ERROR); + vma_put_file_ref(orig_vma); goto spf_abort; } fault = do_handle_mm_fault(vma, address, flags | FAULT_FLAG_SPECULATIVE, seq, regs); + vma_put_file_ref(orig_vma); if (!(fault & VM_FAULT_RETRY)) goto done;