vsyscall emulation compatibility fixes
Subsystems (3)
cover vsyscall emulation compatibility fixes
This is the latest attempt to make vsyscall emulation compatible with dynamic insrumentation tools like DynamoRIO and pin
(http://pintool.org). They make assumptions about how the int instruction works that were false with the original vsyscall emulation code.
There is now a vsyscall boot parameter. In "native" mode, vsyscalls are just syscall instructions. Emulation works fine. In "emulate" mode (default), vsyscalls appear to be syscall instructions, but attempts to execute them are trapped by the NX bit and the instructions are emulated instead. This is slower than the old interrupt-based code (because I hooked a slow path in the page fault code) but it means that nothing too sneaky goes on behind the backs of the tools. In "none" mode, vsyscalls send SIGSEGV just like any other attempt to execute from an NX page.
This still has corner cases. For example, single-stepping through a vsyscall will step across the whole thing instead of across just one instruction. I suspect that nothing cares. Somewhat more significantly, if an exploit (or exploit-like program) jumps to a syscall instruction in the vsyscall page under pin, then it will work, whereas without pin in vsyscall=emulate mode, it would receive SIGSEGV. Pin is welcome to fix this corner case if it cares.
If this still causes problems, we can just default the vsyscall parameter to native for 3.1
The first patch is pure cleanup and is not required. The second patch wires up the getcpu syscall and is required for the native code to work. The third patch is the meat.
For extra points, if you ignore the documentation in kernel-parameters.txt, this patch set removes more lines than it adds.
Andy Lutomirski (3):
x86: Remove unnecessary compile flag tweaks for vsyscall code
x86-64: Wire up getcpu syscall
x86-64: Rework vsyscall emulation and add vsyscall= parameter
Documentation/kernel-parameters.txt | 21 +++++++++ arch/x86/include/asm/irq_vectors.h | 4 -- arch/x86/include/asm/traps.h | 2 - arch/x86/include/asm/unistd_64.h | 2 + arch/x86/include/asm/vsyscall.h | 6 +++ arch/x86/kernel/Makefile | 13 ------ arch/x86/kernel/entry_64.S | 1 - arch/x86/kernel/traps.c | 6 --- arch/x86/kernel/vmlinux.lds.S | 33 -------------- arch/x86/kernel/vsyscall_64.c | 82 +++++++++++++++++++++-------------- arch/x86/kernel/vsyscall_emu_64.S | 36 ++++++++++------ arch/x86/mm/fault.c | 12 +++++ 12 files changed, 113 insertions(+), 105 deletions(-)
Signature · 1 line
1.7.6
PATCH 1/3 x86: Remove unnecessary compile flag tweaks for vsyscall code
As of commit 98d0ac38ca7b1b7a552c9a2359174ff84decb600
Author: Andy Lutomirski <[email protected]> Date: Thu Jul 14 06:47:22 2011 -0400
x86-64: Move vread_tsc and vread_hpet into the vDSO
user code no longer directly calls into code in arch/x86/kernel/, so we don't need compile flag hacks to make it safe. All vdso code is in the vdso directory now.
--- arch/x86/kernel/Makefile | 13 ------------- arch/x86/kernel/vsyscall_64.c | 3 --- 2 files changed, 0 insertions(+), 16 deletions(-)
arch/x86/kernel/Makefile +0 -13
@@ -17,19 +17,6 @@ CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_early_printk.o = -pg endif -# -# vsyscalls (which work on the user stack) should have -# no stack-protector checks: -# -nostackp := $(call cc-option, -fno-stack-protector) -CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) -CFLAGS_hpet.o := $(nostackp) -CFLAGS_paravirt.o := $(nostackp) -GCOV_PROFILE_vsyscall_64.o := n -GCOV_PROFILE_hpet.o := n -GCOV_PROFILE_tsc.o := n -GCOV_PROFILE_paravirt.o := n - obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time.o ioport.o ldt.o dumpstack.o
arch/x86/kernel/vsyscall_64.c +0 -3
@@ -18,9 +18,6 @@* use the vDSO. */ -/* Disable profiling for userspace code: */ -#define DISABLE_BRANCH_PROFILING -#include <linux/time.h> #include <linux/init.h> #include <linux/kernel.h>
Signature · 1 line
1.7.6
[tip:x86/vdso] x86: Remove unnecessary compile flag tweaks for vsyscall code
Commit-ID: f3fb5b7bb70d6e679c15fef85707810a067f5fb6 Gitweb: http://git.kernel.org/tip/f3fb5b7bb70d6e679c15fef85707810a067f5fb6 Author: Andy Lutomirski <[email protected]> AuthorDate: Wed, 10 Aug 2011 11:15:30 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Wed, 10 Aug 2011 18:55:29 -0500
x86: Remove unnecessary compile flag tweaks for vsyscall code
As of commit 98d0ac38ca7b1b7a552c9a2359174ff84decb600
Author: Andy Lutomirski <[email protected]> Date: Thu Jul 14 06:47:22 2011 -0400
x86-64: Move vread_tsc and vread_hpet into the vDSO
user code no longer directly calls into code in arch/x86/kernel/, so we don't need compile flag hacks to make it safe. All vdso code is in the vdso directory now.
--- arch/x86/kernel/Makefile | 13 ------------- arch/x86/kernel/vsyscall_64.c | 3 --- 2 files changed, 0 insertions(+), 16 deletions(-)
arch/x86/kernel/Makefile +0 -13
@@ -17,19 +17,6 @@ CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_early_printk.o = -pg endif -# -# vsyscalls (which work on the user stack) should have -# no stack-protector checks: -# -nostackp := $(call cc-option, -fno-stack-protector) -CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) -CFLAGS_hpet.o := $(nostackp) -CFLAGS_paravirt.o := $(nostackp) -GCOV_PROFILE_vsyscall_64.o := n -GCOV_PROFILE_hpet.o := n -GCOV_PROFILE_tsc.o := n -GCOV_PROFILE_paravirt.o := n - obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += time.o ioport.o ldt.o dumpstack.o
arch/x86/kernel/vsyscall_64.c +0 -3
@@ -18,9 +18,6 @@* use the vDSO. */ -/* Disable profiling for userspace code: */ -#define DISABLE_BRANCH_PROFILING -#include <linux/time.h> #include <linux/init.h> #include <linux/kernel.h>
PATCH 2/3 x86-64: Wire up getcpu syscall
In reply to Andy Lutomirskigetcpu is available as a vdso entry and an emulated vsyscall. Programs that for some reason don't want to use the vdso should still be able to call getcpu without relying on the slow emulated vsyscall. It costs almost nothing to expose it as a real syscall.
We also need this for the following patch in vsyscall=native mode.
--- arch/x86/include/asm/unistd_64.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/include/asm/unistd_64.h +2 -0
@@ -681,6 +681,8 @@ __SYSCALL(__NR_syncfs, sys_syncfs) __SYSCALL(__NR_sendmmsg, sys_sendmmsg)#define __NR_setns 308 __SYSCALL(__NR_setns, sys_setns) +#define __NR_getcpu 309 +__SYSCALL(__NR_getcpu, sys_getcpu)#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
Signature · 1 line
1.7.6
[tip:x86/vdso] x86-64: Wire up getcpu syscall
Commit-ID: 8df77470aa0d3b101a481197de4c6d9716ee63bc Gitweb: http://git.kernel.org/tip/8df77470aa0d3b101a481197de4c6d9716ee63bc Author: Andy Lutomirski <[email protected]> AuthorDate: Wed, 10 Aug 2011 11:15:31 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Wed, 10 Aug 2011 18:55:48 -0500
x86-64: Wire up getcpu syscall
getcpu is available as a vdso entry and an emulated vsyscall. Programs that for some reason don't want to use the vdso should still be able to call getcpu without relying on the slow emulated vsyscall. It costs almost nothing to expose it as a real syscall.
We also need this for the following patch in vsyscall=native mode.
--- arch/x86/include/asm/unistd_64.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/include/asm/unistd_64.h +2 -0
@@ -681,6 +681,8 @@ __SYSCALL(__NR_syncfs, sys_syncfs) __SYSCALL(__NR_sendmmsg, sys_sendmmsg)#define __NR_setns 308 __SYSCALL(__NR_setns, sys_setns) +#define __NR_getcpu 309 +__SYSCALL(__NR_getcpu, sys_getcpu)#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
[tip:x86/vdso] x86-64: Wire up getcpu syscall
In reply to Andy LutomirskiCommit-ID: fce8dc06423d6fb2709469dc5c55b04e09c1d126 Gitweb: http://git.kernel.org/tip/fce8dc06423d6fb2709469dc5c55b04e09c1d126 Author: Andy Lutomirski <[email protected]> AuthorDate: Wed, 10 Aug 2011 11:15:31 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Wed, 10 Aug 2011 19:26:46 -0500
x86-64: Wire up getcpu syscall
getcpu is available as a vdso entry and an emulated vsyscall. Programs that for some reason don't want to use the vdso should still be able to call getcpu without relying on the slow emulated vsyscall. It costs almost nothing to expose it as a real syscall.
We also need this for the following patch in vsyscall=native mode.
--- arch/x86/include/asm/unistd_64.h | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
arch/x86/include/asm/unistd_64.h +2 -0
@@ -681,6 +681,8 @@ __SYSCALL(__NR_syncfs, sys_syncfs) __SYSCALL(__NR_sendmmsg, sys_sendmmsg)#define __NR_setns 308 __SYSCALL(__NR_setns, sys_setns) +#define __NR_getcpu 309 +__SYSCALL(__NR_getcpu, sys_getcpu)#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
PATCH 3/3 x86-64: Rework vsyscall emulation and add vsyscall= parameter
In reply to Andy LutomirskiThere are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the bad_area path. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.
vsyscall=none: Trying to execute a vsyscall will segfault.
--- Documentation/kernel-parameters.txt | 21 +++++++++ arch/x86/include/asm/irq_vectors.h | 4 -- arch/x86/include/asm/traps.h | 2 - arch/x86/include/asm/vsyscall.h | 6 +++ arch/x86/kernel/entry_64.S | 1 - arch/x86/kernel/traps.c | 6 --- arch/x86/kernel/vmlinux.lds.S | 33 -------------- arch/x86/kernel/vsyscall_64.c | 79 +++++++++++++++++++++------------- arch/x86/kernel/vsyscall_emu_64.S | 36 ++++++++++------ arch/x86/mm/fault.c | 12 +++++ 10 files changed, 111 insertions(+), 89 deletions(-)
Documentation/kernel-parameters.txt +21 -0
@@ -2680,6 +2680,27 @@ bytes respectively. Such letter suffixes can also be entirely omitted. vmpoff= [KNL,S390] Perform z/VM CP command after power off. Format: <command> + vsyscall= [X86-64] + Controls the behavior of vsyscalls (i.e. calls to + fixed addresses of 0xffffffffff600x00 from legacy + code). Most statically-linked binaries and older + versions of glibc use these calls. Because these + functions are at fixed addresses, they make nice + targets for exploits that can control RIP. + + emulate [default] Vsyscalls turn into traps and are + emulated reasonably safely. + + native Vsyscalls are native syscall instructions. + This is a little bit faster than trapping + and makes a few dynamic recompilers work + better than they would in emulation mode. + It also makes exploits much easier to write. + + none Vsyscalls don't work at all. This makes + them quite hard to use for exploits but + might break your system. + vt.cur_default= [VT] Default cursor shape. Format: 0xCCBBAA, where AA, BB, and CC are the same as the parameters of the <Esc>[?A;B;Cc escape sequence;
arch/x86/include/asm/irq_vectors.h +0 -4
@@ -17,7 +17,6 @@* Vectors 0 ... 31 : system traps and exceptions - hardcoded events * Vectors 32 ... 127 : device interrupts * Vector 128 : legacy int80 syscall interface -* Vector 204 : legacy x86_64 vsyscall emulation * Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts * Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts *
@@ -51,9 +50,6 @@#ifdef CONFIG_X86_32 # define SYSCALL_VECTOR 0x80#endif -#ifdef CONFIG_X86_64 -# define VSYSCALL_EMU_VECTOR 0xcc -#endif /* * Vectors 0x30-0x3f are used for ISA interrupts.
arch/x86/include/asm/traps.h +0 -2
@@ -40,7 +40,6 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void);#endif /* CONFIG_X86_MCE */ asmlinkage void simd_coprocessor_error(void); -asmlinkage void emulate_vsyscall(void); dotraplinkage void do_divide_error(struct pt_regs *, long); dotraplinkage void do_debug(struct pt_regs *, long);
@@ -67,7 +66,6 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long); dotraplinkage void do_machine_check(struct pt_regs *, long);#endif dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); -dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long);#ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *, long);#endif
arch/x86/include/asm/vsyscall.h +6 -0
@@ -27,6 +27,12 @@ extern struct timezone sys_tz;extern void map_vsyscall (void ); +/* +* Called on instruction fetch fault in vsyscall page. +* Returns true if handled. +*/ +extern bool emulate_vsyscall (struct pt_regs *regs,unsigned long address); +#endif /* __KERNEL__ */ #endif /* _ASM_X86_VSYSCALL_H */
arch/x86/kernel/entry_64.S +0 -1
@@ -1111,7 +1111,6 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug zeroentry coprocessor_error do_coprocessor_error errorentry alignment_check do_alignment_check zeroentry simd_coprocessor_error do_simd_coprocessor_error -zeroentry emulate_vsyscall do_emulate_vsyscall /* Reload gs selector with exception handling */
arch/x86/kernel/traps.c +0 -6
@@ -872,12 +872,6 @@ void __init trap_init(void)set_bit (SYSCALL_VECTOR , used_vectors);#endif -#ifdef CONFIG_X86_64 -BUG_ON (test_bit (VSYSCALL_EMU_VECTOR , used_vectors)); -set_system_intr_gate (VSYSCALL_EMU_VECTOR , &emulate_vsyscall); -set_bit (VSYSCALL_EMU_VECTOR , used_vectors); -#endif -/* * Should be a barrier for any external CPU state: */
arch/x86/kernel/vmlinux.lds.S +0 -33
@@ -71,7 +71,6 @@ PHDRS { text PT_LOAD FLAGS(5); /* R_E */ data PT_LOAD FLAGS(6); /* RW_ */ #ifdef CONFIG_X86_64 - user PT_LOAD FLAGS(5); /* R_E */ #ifdef CONFIG_SMP percpu PT_LOAD FLAGS(6); /* RW_ */ #endif
@@ -174,38 +173,6 @@ SECTIONS . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE); -#define VSYSCALL_ADDR (-10*1024*1024) - -#define VLOAD_OFFSET (VSYSCALL_ADDR - __vsyscall_0 + LOAD_OFFSET) -#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) - -#define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0) -#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) - - __vsyscall_0 = .; - - . = VSYSCALL_ADDR; - .vsyscall : AT(VLOAD(.vsyscall)) { - /* work around gold bug 13023 */ - __vsyscall_beginning_hack = .; - *(.vsyscall_0) - - . = __vsyscall_beginning_hack + 1024; - *(.vsyscall_1) - - . = __vsyscall_beginning_hack + 2048; - *(.vsyscall_2) - - . = __vsyscall_beginning_hack + 4096; /* Pad the whole page. */ - } :user =0xcc - . = ALIGN(__vsyscall_0 + PAGE_SIZE, PAGE_SIZE); - -#undef VSYSCALL_ADDR -#undef VLOAD_OFFSET -#undef VLOAD -#undef VVIRT_OFFSET -#undef VVIRT - #endif /* CONFIG_X86_64 */ /* Init code and data - will be freed after init */
arch/x86/kernel/vsyscall_64.c +49 -30
135 lines not on this page · raw message
arch/x86/kernel/vsyscall_emu_64.S +23 -13
@@ -7,21 +7,31 @@ */ #include <linux/linkage.h> + #include <asm/irq_vectors.h> +#include <asm/page_types.h> +#include <asm/unistd_64.h> + +__PAGE_ALIGNED_DATA + .globl __vsyscall_page + .balign PAGE_SIZE, 0xcc + .type __vsyscall_page, @object +__vsyscall_page: + + mov $__NR_gettimeofday, %rax + syscall + ret -/* The unused parts of the page are filled with 0xcc by the linker script. */ + .balign 1024, 0xcc + mov $__NR_time, %rax + syscall + ret -.section .vsyscall_0, "a" -ENTRY(vsyscall_0) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_0) + .balign 1024, 0xcc + mov $__NR_getcpu, %rax + syscall + ret -.section .vsyscall_1, "a" -ENTRY(vsyscall_1) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_1) + .balign 4096, 0xcc -.section .vsyscall_2, "a" -ENTRY(vsyscall_2) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_2) + .size __vsyscall_page, 4096
arch/x86/mm/fault.c +12 -0
@@ -720,6 +720,18 @@ __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 &PF_INSTR ) && + ((address & ~0xfff ) ==VSYSCALL_START ))) { +if (emulate_vsyscall (regs, address)) +return ; + } +#endif +if (unlikely (show_unhandled_signals))show_signal_msg (regs, error_code, address, tsk);
Signature · 1 line
1.7.6
H. Peter Anvin
reviewerRe: [PATCH 3/3] x86-64: Rework vsyscall emulation and add vsyscall= parameter
Quoted 12 lines · Andy Lutomirski
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the
bad_areapath. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.
Quoted 3 lines
vsyscall=none: Trying to execute a vsyscall will segfault.
Signed-off-by Andy Lutomirski <[email protected]>
Hi Andy,
This patch doesn't apply. What is your baseline for this patch?
-hpa
Re: [PATCH 3/3] x86-64: Rework vsyscall emulation and add vsyscall= parameter
Quoted 13 lines · H. Peter Anvin
Quoted 12 lines · Andy Lutomirski
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the
bad_areapath. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.
Quoted 7 lines
Quoted 3 lines
vsyscall=none: Trying to execute a vsyscall will segfault.
Signed-off-by Andy Lutomirski <[email protected]>Hi Andy,
This patch doesn't apply. What is your baseline for this patch?
My baseline was a commit that probably only lives in my tree, but the patches should apply cleanly on top of c149a665ac488e0dac22a42287f45ad1bda06ff1, which is the current tip/x86/vdso.
--Andy
H. Peter Anvin
reviewerRe: [PATCH 3/3] x86-64: Rework vsyscall emulation and add vsyscall= parameter
Quoted 20 lines · Andrew Lutomirski
Quoted 19 lines · H. Peter Anvin
Quoted 12 lines · Andy Lutomirski
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the
bad_areapath. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.Quoted 3 lines
vsyscall=none: Trying to execute a vsyscall will segfault.
Signed-off-by Andy Lutomirski <[email protected]>Hi Andy,
Quoted 8 lines
Quoted 1 line
This patch doesn't apply. What is your baseline for this patch?
My baseline was a commit that probably only lives in my tree, but the patches should apply cleanly on top of
c149a665ac488e0dac22a42287f45ad1bda06ff1, which is the current tip/x86/vdso.--Andy
Please rebase your patch on the current -linus since it appears to have changed since x86/vdso was merged.
-hpa
Signature · 1 line
Sent from my mobile phone. Please excuse my brevity and lack of formatting.
Re: [PATCH 3/3] x86-64: Rework vsyscall emulation and add vsyscall= parameter
Quoted 24 lines · H. Peter Anvin
Quoted 22 lines · Andrew Lutomirski
Quoted 20 lines · H. Peter Anvin
Quoted 12 lines · Andy Lutomirski
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the
bad_areapath. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.Quoted 3 lines
vsyscall=none: Trying to execute a vsyscall will segfault.
Signed-off-by Andy Lutomirski <[email protected]>Hi Andy,
This patch doesn't apply. What is your baseline for this patch?
Quoted 9 lines
Quoted 6 lines
My baseline was a commit that probably only lives in my tree, but the patches should apply cleanly on top of
c149a665ac488e0dac22a42287f45ad1bda06ff1, which is the current tip/x86/vdso.--Andy
Please rebase your patch on the current -linus since it appears to have changed since x86/vdso was merged.
Can you double-check? I think it's the other way around: x86/vdso has fixes that should be pushed to Linus.
$ git log tip/x86/vdso ^origin/master --oneline c149a66 x86-64: Add vsyscall:emulate_vsyscall trace event 318f5a2 x86-64: Add user_64bit_mode paravirt op 5d5791a x86-64, xen: Enable the vvar mapping f670bb7 x86-64: Work around gold bug 13023 9c40818 x86-64: Move the "user" vsyscall segment out of the data segment. 1bdfac1 x86-64: Pad vDSO to a page boundary 17b0436 Merge commit 'v3.0' into x86/vdso
--Andy
H. Peter Anvin
reviewerRe: [PATCH 3/3] x86-64: Rework vsyscall emulation and add vsyscall= parameter
Quoted 51 lines · Andrew Lutomirski
Quoted 3 lines · H. Peter Anvin
Quoted 1 line · Andrew Lutomirski
On Wed, Aug 10, 2011 at 1:21 PM, H. Peter Anvin <[email protected]>
Quoted 10 lines · wrote:
Quoted 10 lines
Quoted 10 lines · Andy Lutomirski
Quoted 9 lines
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the
bad_areapath. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptionsabout
Quoted 11 lines
Quoted 11 lines
Quoted 10 lines
Quoted 6 lines
what the code in the page does will not be confused when they read that code.
vsyscall=none: Trying to execute a vsyscall will segfault.
Signed-off-by Andy Lutomirski <[email protected]>Hi Andy,
This patch doesn't apply. What is your baseline for this patch?
Quoted 8 lines
Quoted 6 lines
My baseline was a commit that probably only lives in my tree, but the patches should apply cleanly on top of
c149a665ac488e0dac22a42287f45ad1bda06ff1, which is the current tip/x86/vdso.--Andy
Please rebase your patch on the current -linus since it appears to
have changed since x86/vdso was merged.
Quoted 1 line
Can you double-check? I think it's the other way around: x86/vdso has fixes that should be pushed to Linus.
$ git log tip/x86/vdso ^origin/master --oneline c149a66 x86-64: Add vsyscall:emulate_vsyscall trace event 318f5a2 x86-64: Add user_64bit_mode paravirt op 5d5791a x86-64, xen: Enable the vvar mapping f670bb7 x86-64: Work around gold bug 13023 9c40818 x86-64: Move the "user" vsyscall segment out of the data segment. 1bdfac1 x86-64: Pad vDSO to a page boundary 17b0436 Merge commit 'v3.0' into x86/vdso
Quoted 1 line
--Andy
You're right, although coupling it makes the testing harder.
Signature · 1 line
Sent from my mobile phone. Please excuse my brevity and lack of formatting.
Re: [PATCH 3/3] x86-64: Rework vsyscall emulation and add vsyscall= parameter
Quoted 21 lines · H. Peter Anvin
Quoted 19 lines · Andrew Lutomirski
Quoted 2 lines · H. Peter Anvin
Please rebase your patch on the current -linus since it appears to
have changed since x86/vdso was merged.
Quoted 1 line
Can you double-check? I think it's the other way around: x86/vdso has fixes that should be pushed to Linus.
$ git log tip/x86/vdso ^origin/master --oneline c149a66 x86-64: Add vsyscall:emulate_vsyscall trace event 318f5a2 x86-64: Add user_64bit_mode paravirt op 5d5791a x86-64, xen: Enable the vvar mapping f670bb7 x86-64: Work around gold bug 13023 9c40818 x86-64: Move the "user" vsyscall segment out of the data segment. 1bdfac1 x86-64: Pad vDSO to a page boundary 17b0436 Merge commit 'v3.0' into x86/vdso
Quoted 3 lines
Quoted 1 line
--Andy
You're right, although coupling it makes the testing harder.
If it helps, I can probably generate a new series that merges 9c40818 with the latest patch and makes the result independent of the rest (except for the trace event). I'm not sure it's worth it, though.
--Andy
[tip:x86/vdso] x86-64: Rework vsyscall emulation and add vsyscall= parameter
In reply to Andy LutomirskiCommit-ID: 721eb1343cdb53aa1c3b6b35f40976b7328faab0 Gitweb: http://git.kernel.org/tip/721eb1343cdb53aa1c3b6b35f40976b7328faab0 Author: Andy Lutomirski <[email protected]> AuthorDate: Wed, 10 Aug 2011 11:15:32 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Wed, 10 Aug 2011 18:56:01 -0500
x86-64: Rework vsyscall emulation and add vsyscall= parameter
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the bad_area path. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.
vsyscall=none: Trying to execute a vsyscall will segfault.
--- Documentation/kernel-parameters.txt | 21 +++++++++ arch/x86/include/asm/irq_vectors.h | 4 -- arch/x86/include/asm/traps.h | 2 - arch/x86/include/asm/vsyscall.h | 6 +++ arch/x86/kernel/entry_64.S | 1 - arch/x86/kernel/traps.c | 6 --- arch/x86/kernel/vmlinux.lds.S | 33 -------------- arch/x86/kernel/vsyscall_64.c | 79 +++++++++++++++++++++------------- arch/x86/kernel/vsyscall_emu_64.S | 36 ++++++++++------ arch/x86/mm/fault.c | 12 +++++ 10 files changed, 111 insertions(+), 89 deletions(-)
Documentation/kernel-parameters.txt +21 -0
@@ -2657,6 +2657,27 @@ bytes respectively. Such letter suffixes can also be entirely omitted. vmpoff= [KNL,S390] Perform z/VM CP command after power off. Format: <command> + vsyscall= [X86-64] + Controls the behavior of vsyscalls (i.e. calls to + fixed addresses of 0xffffffffff600x00 from legacy + code). Most statically-linked binaries and older + versions of glibc use these calls. Because these + functions are at fixed addresses, they make nice + targets for exploits that can control RIP. + + emulate [default] Vsyscalls turn into traps and are + emulated reasonably safely. + + native Vsyscalls are native syscall instructions. + This is a little bit faster than trapping + and makes a few dynamic recompilers work + better than they would in emulation mode. + It also makes exploits much easier to write. + + none Vsyscalls don't work at all. This makes + them quite hard to use for exploits but + might break your system. + vt.cur_default= [VT] Default cursor shape. Format: 0xCCBBAA, where AA, BB, and CC are the same as the parameters of the <Esc>[?A;B;Cc escape sequence;
arch/x86/include/asm/irq_vectors.h +0 -4
@@ -17,7 +17,6 @@* Vectors 0 ... 31 : system traps and exceptions - hardcoded events * Vectors 32 ... 127 : device interrupts * Vector 128 : legacy int80 syscall interface -* Vector 204 : legacy x86_64 vsyscall emulation * Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts * Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts *
@@ -51,9 +50,6 @@#ifdef CONFIG_X86_32 # define SYSCALL_VECTOR 0x80#endif -#ifdef CONFIG_X86_64 -# define VSYSCALL_EMU_VECTOR 0xcc -#endif /* * Vectors 0x30-0x3f are used for ISA interrupts.
arch/x86/include/asm/traps.h +0 -2
@@ -40,7 +40,6 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void);#endif /* CONFIG_X86_MCE */ asmlinkage void simd_coprocessor_error(void); -asmlinkage void emulate_vsyscall(void); dotraplinkage void do_divide_error(struct pt_regs *, long); dotraplinkage void do_debug(struct pt_regs *, long);
@@ -67,7 +66,6 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long); dotraplinkage void do_machine_check(struct pt_regs *, long);#endif dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); -dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long);#ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *, long);#endif
arch/x86/include/asm/vsyscall.h +6 -0
@@ -27,6 +27,12 @@ extern struct timezone sys_tz;extern void map_vsyscall (void ); +/* +* Called on instruction fetch fault in vsyscall page. +* Returns true if handled. +*/ +extern bool emulate_vsyscall (struct pt_regs *regs,unsigned long address); +#endif /* __KERNEL__ */ #endif /* _ASM_X86_VSYSCALL_H */
arch/x86/kernel/entry_64.S +0 -1
@@ -1123,7 +1123,6 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug zeroentry coprocessor_error do_coprocessor_error errorentry alignment_check do_alignment_check zeroentry simd_coprocessor_error do_simd_coprocessor_error -zeroentry emulate_vsyscall do_emulate_vsyscall /* Reload gs selector with exception handling */
arch/x86/kernel/traps.c +0 -6
@@ -872,12 +872,6 @@ void __init trap_init(void)set_bit (SYSCALL_VECTOR , used_vectors);#endif -#ifdef CONFIG_X86_64 -BUG_ON (test_bit (VSYSCALL_EMU_VECTOR , used_vectors)); -set_system_intr_gate (VSYSCALL_EMU_VECTOR , &emulate_vsyscall); -set_bit (VSYSCALL_EMU_VECTOR , used_vectors); -#endif -/* * Should be a barrier for any external CPU state: */
arch/x86/kernel/vmlinux.lds.S +0 -33
@@ -71,7 +71,6 @@ PHDRS { text PT_LOAD FLAGS(5); /* R_E */ data PT_LOAD FLAGS(6); /* RW_ */ #ifdef CONFIG_X86_64 - user PT_LOAD FLAGS(5); /* R_E */ #ifdef CONFIG_SMP percpu PT_LOAD FLAGS(6); /* RW_ */ #endif
@@ -174,38 +173,6 @@ SECTIONS . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE); -#define VSYSCALL_ADDR (-10*1024*1024) - -#define VLOAD_OFFSET (VSYSCALL_ADDR - __vsyscall_0 + LOAD_OFFSET) -#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) - -#define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0) -#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) - - __vsyscall_0 = .; - - . = VSYSCALL_ADDR; - .vsyscall : AT(VLOAD(.vsyscall)) { - /* work around gold bug 13023 */ - __vsyscall_beginning_hack = .; - *(.vsyscall_0) - - . = __vsyscall_beginning_hack + 1024; - *(.vsyscall_1) - - . = __vsyscall_beginning_hack + 2048; - *(.vsyscall_2) - - . = __vsyscall_beginning_hack + 4096; /* Pad the whole page. */ - } :user =0xcc - . = ALIGN(__vsyscall_0 + PAGE_SIZE, PAGE_SIZE); - -#undef VSYSCALL_ADDR -#undef VLOAD_OFFSET -#undef VLOAD -#undef VVIRT_OFFSET -#undef VVIRT - #endif /* CONFIG_X86_64 */ /* Init code and data - will be freed after init */
arch/x86/kernel/vsyscall_64.c +49 -30
135 lines not on this page · raw message
arch/x86/kernel/vsyscall_emu_64.S +23 -13
@@ -7,21 +7,31 @@ */ #include <linux/linkage.h> + #include <asm/irq_vectors.h> +#include <asm/page_types.h> +#include <asm/unistd_64.h> + +__PAGE_ALIGNED_DATA + .globl __vsyscall_page + .balign PAGE_SIZE, 0xcc + .type __vsyscall_page, @object +__vsyscall_page: + + mov $__NR_gettimeofday, %rax + syscall + ret -/* The unused parts of the page are filled with 0xcc by the linker script. */ + .balign 1024, 0xcc + mov $__NR_time, %rax + syscall + ret -.section .vsyscall_0, "a" -ENTRY(vsyscall_0) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_0) + .balign 1024, 0xcc + mov $__NR_getcpu, %rax + syscall + ret -.section .vsyscall_1, "a" -ENTRY(vsyscall_1) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_1) + .balign 4096, 0xcc -.section .vsyscall_2, "a" -ENTRY(vsyscall_2) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_2) + .size __vsyscall_page, 4096
arch/x86/mm/fault.c +12 -0
@@ -720,6 +720,18 @@ __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 &PF_INSTR ) && + ((address & ~0xfff ) ==VSYSCALL_START ))) { +if (emulate_vsyscall (regs, address)) +return ; + } +#endif +if (unlikely (show_unhandled_signals))show_signal_msg (regs, error_code, address, tsk);
[tip:x86/vdso] x86-64: Rework vsyscall emulation and add vsyscall= parameter
In reply to Andy LutomirskiCommit-ID: 3ae36655b97a03fa1decf72f04078ef945647c1a Gitweb: http://git.kernel.org/tip/3ae36655b97a03fa1decf72f04078ef945647c1a Author: Andy Lutomirski <[email protected]> AuthorDate: Wed, 10 Aug 2011 11:15:32 -0400 Committer: H. Peter Anvin <[email protected]> CommitDate: Wed, 10 Aug 2011 19:26:46 -0500
x86-64: Rework vsyscall emulation and add vsyscall= parameter
There are three choices:
vsyscall=native: Vsyscalls are native code that issues the corresponding syscalls.
vsyscall=emulate (default): Vsyscalls are emulated by instruction fault traps, tested in the bad_area path. The actual contents of the vsyscall page is the same as the vsyscall=native case except that it's marked NX. This way programs that make assumptions about what the code in the page does will not be confused when they read that code.
vsyscall=none: Trying to execute a vsyscall will segfault.
--- Documentation/kernel-parameters.txt | 21 +++++++++ arch/x86/include/asm/irq_vectors.h | 4 -- arch/x86/include/asm/traps.h | 2 - arch/x86/include/asm/vsyscall.h | 6 +++ arch/x86/kernel/entry_64.S | 1 - arch/x86/kernel/traps.c | 6 --- arch/x86/kernel/vmlinux.lds.S | 33 -------------- arch/x86/kernel/vsyscall_64.c | 79 +++++++++++++++++++++------------- arch/x86/kernel/vsyscall_emu_64.S | 36 ++++++++++------ arch/x86/mm/fault.c | 12 +++++ 10 files changed, 111 insertions(+), 89 deletions(-)
Documentation/kernel-parameters.txt +21 -0
@@ -2657,6 +2657,27 @@ bytes respectively. Such letter suffixes can also be entirely omitted. vmpoff= [KNL,S390] Perform z/VM CP command after power off. Format: <command> + vsyscall= [X86-64] + Controls the behavior of vsyscalls (i.e. calls to + fixed addresses of 0xffffffffff600x00 from legacy + code). Most statically-linked binaries and older + versions of glibc use these calls. Because these + functions are at fixed addresses, they make nice + targets for exploits that can control RIP. + + emulate [default] Vsyscalls turn into traps and are + emulated reasonably safely. + + native Vsyscalls are native syscall instructions. + This is a little bit faster than trapping + and makes a few dynamic recompilers work + better than they would in emulation mode. + It also makes exploits much easier to write. + + none Vsyscalls don't work at all. This makes + them quite hard to use for exploits but + might break your system. + vt.cur_default= [VT] Default cursor shape. Format: 0xCCBBAA, where AA, BB, and CC are the same as the parameters of the <Esc>[?A;B;Cc escape sequence;
arch/x86/include/asm/irq_vectors.h +0 -4
@@ -17,7 +17,6 @@* Vectors 0 ... 31 : system traps and exceptions - hardcoded events * Vectors 32 ... 127 : device interrupts * Vector 128 : legacy int80 syscall interface -* Vector 204 : legacy x86_64 vsyscall emulation * Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts * Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts *
@@ -51,9 +50,6 @@#ifdef CONFIG_X86_32 # define SYSCALL_VECTOR 0x80#endif -#ifdef CONFIG_X86_64 -# define VSYSCALL_EMU_VECTOR 0xcc -#endif /* * Vectors 0x30-0x3f are used for ISA interrupts.
arch/x86/include/asm/traps.h +0 -2
@@ -40,7 +40,6 @@ asmlinkage void alignment_check(void); asmlinkage void machine_check(void);#endif /* CONFIG_X86_MCE */ asmlinkage void simd_coprocessor_error(void); -asmlinkage void emulate_vsyscall(void); dotraplinkage void do_divide_error(struct pt_regs *, long); dotraplinkage void do_debug(struct pt_regs *, long);
@@ -67,7 +66,6 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long); dotraplinkage void do_machine_check(struct pt_regs *, long);#endif dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); -dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long);#ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *, long);#endif
arch/x86/include/asm/vsyscall.h +6 -0
@@ -27,6 +27,12 @@ extern struct timezone sys_tz;extern void map_vsyscall (void ); +/* +* Called on instruction fetch fault in vsyscall page. +* Returns true if handled. +*/ +extern bool emulate_vsyscall (struct pt_regs *regs,unsigned long address); +#endif /* __KERNEL__ */ #endif /* _ASM_X86_VSYSCALL_H */
arch/x86/kernel/entry_64.S +0 -1
@@ -1123,7 +1123,6 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug zeroentry coprocessor_error do_coprocessor_error errorentry alignment_check do_alignment_check zeroentry simd_coprocessor_error do_simd_coprocessor_error -zeroentry emulate_vsyscall do_emulate_vsyscall /* Reload gs selector with exception handling */
arch/x86/kernel/traps.c +0 -6
@@ -872,12 +872,6 @@ void __init trap_init(void)set_bit (SYSCALL_VECTOR , used_vectors);#endif -#ifdef CONFIG_X86_64 -BUG_ON (test_bit (VSYSCALL_EMU_VECTOR , used_vectors)); -set_system_intr_gate (VSYSCALL_EMU_VECTOR , &emulate_vsyscall); -set_bit (VSYSCALL_EMU_VECTOR , used_vectors); -#endif -/* * Should be a barrier for any external CPU state: */
arch/x86/kernel/vmlinux.lds.S +0 -33
@@ -71,7 +71,6 @@ PHDRS { text PT_LOAD FLAGS(5); /* R_E */ data PT_LOAD FLAGS(6); /* RW_ */ #ifdef CONFIG_X86_64 - user PT_LOAD FLAGS(5); /* R_E */ #ifdef CONFIG_SMP percpu PT_LOAD FLAGS(6); /* RW_ */ #endif
@@ -174,38 +173,6 @@ SECTIONS . = ALIGN(__vvar_page + PAGE_SIZE, PAGE_SIZE); -#define VSYSCALL_ADDR (-10*1024*1024) - -#define VLOAD_OFFSET (VSYSCALL_ADDR - __vsyscall_0 + LOAD_OFFSET) -#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) - -#define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0) -#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) - - __vsyscall_0 = .; - - . = VSYSCALL_ADDR; - .vsyscall : AT(VLOAD(.vsyscall)) { - /* work around gold bug 13023 */ - __vsyscall_beginning_hack = .; - *(.vsyscall_0) - - . = __vsyscall_beginning_hack + 1024; - *(.vsyscall_1) - - . = __vsyscall_beginning_hack + 2048; - *(.vsyscall_2) - - . = __vsyscall_beginning_hack + 4096; /* Pad the whole page. */ - } :user =0xcc - . = ALIGN(__vsyscall_0 + PAGE_SIZE, PAGE_SIZE); - -#undef VSYSCALL_ADDR -#undef VLOAD_OFFSET -#undef VLOAD -#undef VVIRT_OFFSET -#undef VVIRT - #endif /* CONFIG_X86_64 */ /* Init code and data - will be freed after init */
arch/x86/kernel/vsyscall_64.c +49 -30
135 lines not on this page · raw message
arch/x86/kernel/vsyscall_emu_64.S +23 -13
@@ -7,21 +7,31 @@ */ #include <linux/linkage.h> + #include <asm/irq_vectors.h> +#include <asm/page_types.h> +#include <asm/unistd_64.h> + +__PAGE_ALIGNED_DATA + .globl __vsyscall_page + .balign PAGE_SIZE, 0xcc + .type __vsyscall_page, @object +__vsyscall_page: + + mov $__NR_gettimeofday, %rax + syscall + ret -/* The unused parts of the page are filled with 0xcc by the linker script. */ + .balign 1024, 0xcc + mov $__NR_time, %rax + syscall + ret -.section .vsyscall_0, "a" -ENTRY(vsyscall_0) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_0) + .balign 1024, 0xcc + mov $__NR_getcpu, %rax + syscall + ret -.section .vsyscall_1, "a" -ENTRY(vsyscall_1) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_1) + .balign 4096, 0xcc -.section .vsyscall_2, "a" -ENTRY(vsyscall_2) - int $VSYSCALL_EMU_VECTOR -END(vsyscall_2) + .size __vsyscall_page, 4096
arch/x86/mm/fault.c +12 -0
@@ -720,6 +720,18 @@ __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 &PF_INSTR ) && + ((address & ~0xfff ) ==VSYSCALL_START ))) { +if (emulate_vsyscall (regs, address)) +return ; + } +#endif +if (unlikely (show_unhandled_signals))show_signal_msg (regs, error_code, address, tsk);