Skip to content

Commit 3ae0ad9

Browse files
hansendcPeter Zijlstra
authored andcommitted
x86/mm/vsyscall: Consider vsyscall page part of user address space
The vsyscall page is weird. It is in what is traditionally part of the kernel address space. But, it has user permissions and we handle faults on it like we would on a user page: interrupts on. Right now, we handle vsyscall emulation in the "bad_area" code, which is used for both user-address-space and kernel-address-space faults. Move the handling to the user-address-space code *only* and ensure we get there by "excluding" the vsyscall page from the kernel address space via a check in fault_in_kernel_space(). Since the fault_in_kernel_space() check is used on 32-bit, also add a 64-bit check to make it clear we only use this path on 64-bit. Also move the unlikely() to be in is_vsyscall_vaddr() itself. This helps clean up the kernel fault handling path by removing a case that can happen in normal[1] operation. (Yeah, yeah, we can argue about the vsyscall page being "normal" or not.) This also makes sanity checks easier, like the "we never take pkey faults in the kernel address space" check in the next patch. Cc: [email protected] Cc: Jann Horn <[email protected]> Cc: Sean Christopherson <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Andy Lutomirski <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: http://lkml.kernel.org/r/[email protected]
1 parent 02e983b commit 3ae0ad9

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

arch/x86/mm/fault.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ show_signal_msg(struct pt_regs *regs, unsigned long error_code,
846846
*/
847847
static bool is_vsyscall_vaddr(unsigned long vaddr)
848848
{
849-
return (vaddr & PAGE_MASK) == VSYSCALL_ADDR;
849+
return unlikely((vaddr & PAGE_MASK) == VSYSCALL_ADDR);
850850
}
851851

852852
static void
@@ -872,18 +872,6 @@ __bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
872872
if (is_errata100(regs, address))
873873
return;
874874

875-
#ifdef CONFIG_X86_64
876-
/*
877-
* Instruction fetch faults in the vsyscall page might need
878-
* emulation.
879-
*/
880-
if (unlikely((error_code & X86_PF_INSTR) &&
881-
is_vsyscall_vaddr(address))) {
882-
if (emulate_vsyscall(regs, address))
883-
return;
884-
}
885-
#endif
886-
887875
/*
888876
* To avoid leaking information about the kernel page table
889877
* layout, pretend that user-mode accesses to kernel addresses
@@ -1192,6 +1180,14 @@ access_error(unsigned long error_code, struct vm_area_struct *vma)
11921180

11931181
static int fault_in_kernel_space(unsigned long address)
11941182
{
1183+
/*
1184+
* On 64-bit systems, the vsyscall page is at an address above
1185+
* TASK_SIZE_MAX, but is not considered part of the kernel
1186+
* address space.
1187+
*/
1188+
if (IS_ENABLED(CONFIG_X86_64) && is_vsyscall_vaddr(address))
1189+
return false;
1190+
11951191
return address >= TASK_SIZE_MAX;
11961192
}
11971193

@@ -1359,6 +1355,22 @@ void do_user_addr_fault(struct pt_regs *regs,
13591355
if (sw_error_code & X86_PF_INSTR)
13601356
flags |= FAULT_FLAG_INSTRUCTION;
13611357

1358+
#ifdef CONFIG_X86_64
1359+
/*
1360+
* Instruction fetch faults in the vsyscall page might need
1361+
* emulation. The vsyscall page is at a high address
1362+
* (>PAGE_OFFSET), but is considered to be part of the user
1363+
* address space.
1364+
*
1365+
* The vsyscall page does not have a "real" VMA, so do this
1366+
* emulation before we go searching for VMAs.
1367+
*/
1368+
if ((sw_error_code & X86_PF_INSTR) && is_vsyscall_vaddr(address)) {
1369+
if (emulate_vsyscall(regs, address))
1370+
return;
1371+
}
1372+
#endif
1373+
13621374
/*
13631375
* Kernel-mode access to the user address space should only occur
13641376
* on well-defined single instructions listed in the exception

0 commit comments

Comments
 (0)