diff options
Diffstat (limited to 'arch/x86/mm/fault.c')
| -rw-r--r-- | arch/x86/mm/fault.c | 38 | 
1 files changed, 25 insertions, 13 deletions
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 7a627ac3a0d2..7e0fa7e24168 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -846,7 +846,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,   */  static bool is_vsyscall_vaddr(unsigned long vaddr)  { -	return (vaddr & PAGE_MASK) == VSYSCALL_ADDR; +	return unlikely((vaddr & PAGE_MASK) == VSYSCALL_ADDR);  }  static void @@ -872,18 +872,6 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,  		if (is_errata100(regs, address))  			return; -#ifdef CONFIG_X86_64 -		/* -		 * Instruction fetch faults in the vsyscall page might need -		 * emulation. -		 */ -		if (unlikely((error_code & X86_PF_INSTR) && -			     is_vsyscall_vaddr(address))) { -			if (emulate_vsyscall(regs, address)) -				return; -		} -#endif -  		/*  		 * To avoid leaking information about the kernel page table  		 * layout, pretend that user-mode accesses to kernel addresses @@ -1192,6 +1180,14 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)  static int fault_in_kernel_space(unsigned long address)  { +	/* +	 * On 64-bit systems, the vsyscall page is at an address above +	 * TASK_SIZE_MAX, but is not considered part of the kernel +	 * address space. +	 */ +	if (IS_ENABLED(CONFIG_X86_64) && is_vsyscall_vaddr(address)) +		return false; +  	return address >= TASK_SIZE_MAX;  } @@ -1359,6 +1355,22 @@ void do_user_addr_fault(struct pt_regs *regs,  	if (sw_error_code & X86_PF_INSTR)  		flags |= FAULT_FLAG_INSTRUCTION; +#ifdef CONFIG_X86_64 +	/* +	 * Instruction fetch faults in the vsyscall page might need +	 * emulation.  The vsyscall page is at a high address +	 * (>PAGE_OFFSET), but is considered to be part of the user +	 * address space. +	 * +	 * The vsyscall page does not have a "real" VMA, so do this +	 * emulation before we go searching for VMAs. +	 */ +	if ((sw_error_code & X86_PF_INSTR) && is_vsyscall_vaddr(address)) { +		if (emulate_vsyscall(regs, address)) +			return; +	} +#endif +  	/*  	 * Kernel-mode access to the user address space should only occur  	 * on well-defined single instructions listed in the exception  | 
