vsyscall tweaks
Subsystems (2)
cover vsyscall tweaks
With the new vsyscall emulation code, int 0xcc's behavior depends on where it is called from. A few dynamic instrumentation tools cleverly copy the instruction out of the vsyscall page and execute it, resulting in a segfault. This is nothing new: sysenter would die in a similar way (unless the code got lucky). The only examples I know of are pin and DynamoRIO -- valgrind is already smart enough not to recompile vsyscalls 0 and 1 and "smart" enough to crash unconditionally on vsyscall 2. I can't test pin because it refuses to run on newfangled things like Linux 3.0+ (and I don't want to muck with my kernel version to run a program that's broken anyway). Patch 1 in this series fixes DynamoRIO in limited testing.
Bug reports against valgrind and DynamoRIO exist, and I haven't managed to get permission to post to pin's message board yet.
The other three patches are minor. Patch 2 removes compile flags that are now unnecessary because vsyscall_64.c does not get called in user mode. Patch 3 wires up the getcpu syscall on x86-64 as further encouragement to stop using the vsyscall. Patch 4 adds a feature-removal-schedule.txt entry suggesting that vsyscalls might be disabled in some configurations some day.
x86 maintainers / Linus: feel free to drop any of patches 2-4. I think the getcpu syscall should be added, though, since it's rather odd to have a "syscall" in the vdso and the vsyscall page that can't be called the old-fashioned way.
Changes from RFC v2:
- Fix some more int 0xcc references.
- Add patches 2-4.
Andy Lutomirski (4):
x86-64: Allow emulated vsyscalls from user addresses
x86: Remove unnecessary compile flag tweaks for vsyscall code
x86-64: Wire up getcpu syscall
Add vsyscalls to feature-removal-schedule.txt
Documentation/feature-removal-schedule.txt | 14 +++ arch/x86/include/asm/irq_vectors.h | 11 ++- arch/x86/include/asm/traps.h | 8 ++- arch/x86/include/asm/unistd_64.h | 2 + arch/x86/kernel/Makefile | 13 --- arch/x86/kernel/entry_64.S | 4 +- arch/x86/kernel/traps.c | 14 +++- arch/x86/kernel/vsyscall_64.c | 131 ++++++++++++++-------------- arch/x86/kernel/vsyscall_emu_64.S | 6 +- 9 files changed, 111 insertions(+), 92 deletions(-)
Signature · 1 line
1.7.6
PATCH 1/4 x86-64: Allow emulated vsyscalls from user addresses
A few dynamic recompilation tools are too clever for their own good. They trace control flow through the vsyscall page and recompile that code somewhere else. Then they expect it to work. DynamoRIO
(http://dynamorio.org/) and supposedly Pin (http://www.pintool.org/) are affected. They crash when tracing programs that use vsyscalls. Valgrind is smart enough not to cause problems. It crashes on the getcpu vsyscall, but that has nothing to do with emulation.
This patch makes each of the three vsyscall entries use a different vector so that they can work when relocated. It assumes that the code that relocates them is okay with the int instruction acting like ret. DynamoRIO at least appears to work. Pin is untestable because it can't handle Linux version 3.0+.
We print an obnoxious (rate-limited) message to the log when this happens. Hopefully it will inspire the JIT tools to learn not to trace into kernel address space.
---
Suresh: can you comment on whether interrupt vectors 0x40-0x42 are good choices?
arch/x86/include/asm/irq_vectors.h | 11 ++-- arch/x86/include/asm/traps.h | 8 ++- arch/x86/kernel/entry_64.S | 4 +- arch/x86/kernel/traps.c | 14 +++- arch/x86/kernel/vsyscall_64.c | 128 ++++++++++++++++++----------------- arch/x86/kernel/vsyscall_emu_64.S | 6 +- 6 files changed, 95 insertions(+), 76 deletions(-)
arch/x86/include/asm/irq_vectors.h +6 -5
@@ -15,10 +15,9 @@* IDT entries: * * 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 32 ... INVALIDATE_TLB_VECTOR_START-1 : device interrupts, except: +* Vectors 64 ... 66 : legacy x86_64 vsyscall emulation +* Vector 128 : legacy int80 syscall interface * Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts * * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
@@ -52,7 +51,9 @@# define SYSCALL_VECTOR 0x80#endif #ifdef CONFIG_X86_64 -# define VSYSCALL_EMU_VECTOR 0xcc +# define VSYSCALL0_EMU_VECTOR 0x40 +# define VSYSCALL1_EMU_VECTOR 0x41 +# define VSYSCALL2_EMU_VECTOR 0x42#endif /*
arch/x86/include/asm/traps.h +6 -2
@@ -40,7 +40,9 @@ 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); +asmlinkage void emulate_vsyscall0(void); +asmlinkage void emulate_vsyscall1(void); +asmlinkage void emulate_vsyscall2(void); dotraplinkage void do_divide_error(struct pt_regs *, long); dotraplinkage void do_debug(struct pt_regs *, long);
@@ -67,7 +69,9 @@ 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); +dotraplinkage void do_emulate_vsyscall0(struct pt_regs *, long); +dotraplinkage void do_emulate_vsyscall1(struct pt_regs *, long); +dotraplinkage void do_emulate_vsyscall2(struct pt_regs *, long);#ifdef CONFIG_X86_32 dotraplinkage void do_iret_error(struct pt_regs *, long);#endif
arch/x86/kernel/entry_64.S +3 -1
@@ -1111,7 +1111,9 @@ 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 +zeroentry emulate_vsyscall0 do_emulate_vsyscall0 +zeroentry emulate_vsyscall1 do_emulate_vsyscall1 +zeroentry emulate_vsyscall2 do_emulate_vsyscall2 /* Reload gs selector with exception handling */
arch/x86/kernel/traps.c +11 -3
@@ -873,9 +873,17 @@ void __init trap_init(void)#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); +BUG_ON (test_bit (VSYSCALL0_EMU_VECTOR , used_vectors)); +set_system_intr_gate (VSYSCALL0_EMU_VECTOR , &emulate_vsyscall0); +set_bit (VSYSCALL0_EMU_VECTOR , used_vectors); + +BUG_ON (test_bit (VSYSCALL1_EMU_VECTOR , used_vectors)); +set_system_intr_gate (VSYSCALL1_EMU_VECTOR , &emulate_vsyscall1); +set_bit (VSYSCALL1_EMU_VECTOR , used_vectors); + +BUG_ON (test_bit (VSYSCALL2_EMU_VECTOR , used_vectors)); +set_system_intr_gate (VSYSCALL2_EMU_VECTOR , &emulate_vsyscall2); +set_bit (VSYSCALL2_EMU_VECTOR , used_vectors);#endif /*
arch/x86/kernel/vsyscall_64.c +66 -62
188 lines not on this page · raw message
arch/x86/kernel/vsyscall_emu_64.S +3 -3
@@ -13,15 +13,15 @@ .section .vsyscall_0, "a" ENTRY(vsyscall_0) - int $VSYSCALL_EMU_VECTOR + int $VSYSCALL0_EMU_VECTOR END(vsyscall_0) .section .vsyscall_1, "a" ENTRY(vsyscall_1) - int $VSYSCALL_EMU_VECTOR + int $VSYSCALL1_EMU_VECTOR END(vsyscall_1) .section .vsyscall_2, "a" ENTRY(vsyscall_2) - int $VSYSCALL_EMU_VECTOR + int $VSYSCALL2_EMU_VECTOR END(vsyscall_2)
Signature · 1 line
1.7.6
H. Peter Anvin
reviewerRe: [PATCH 1/4] x86-64: Allow emulated vsyscalls from user addresses
Quoted 11 lines · Andy Lutomirski
*
* 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 32 ... INVALIDATE_TLB_VECTOR_START-1 : device interrupts, except: + * Vectors 64 ... 66 : legacy x86_64 vsyscall emulation + * Vector 128 : legacy int80 syscall interface* Vectors
INVALIDATE_TLB_VECTOR_START... 255 : special interrupts *
Hi Andy,
Was there a reason to not use the vectors in the 0x2X range?
-hpa
Re: [PATCH 1/4] x86-64: Allow emulated vsyscalls from user addresses
Quoted 13 lines · H. Peter Anvin
Quoted 11 lines · Andy Lutomirski
*
* Vectors 0 ... 31 : system traps and exceptions - hardcoded events
- * Vectors 32 ... 127 : device interrupts
- * Vector 128 : legacy int80 syscall interface
- * Vector 204 : legacyx86_64vsyscall emulation
- * Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 except 204 : device interrupts
+ * Vectors 32 ... INVALIDATE_TLB_VECTOR_START-1 : device interrupts, except:
+ * Vectors 64 ... 66 : legacyx86_64vsyscall emulation
+ * Vector 128 : legacy int80 syscall interface
* VectorsINVALIDATE_TLB_VECTOR_START... 255 : special interrupts *
Quoted 3 lines
Hi Andy,
Was there a reason to not use the vectors in the 0x2X range?
My general lack of understanding of how all the numbers work, and the fact that I was waiting for Suresh to answer. I assumed that /proc/interrupts showed numbers that corresponded to offsets from FIRST_EXTERNAL_VECTOR, in which case the 0x2X range is no good. I think that's wrong and they start at 0x40 (maybe?). This comment in irq_vector.h doesn't help:
/*
* Vectors 0x30-0x3f are used for ISA interrupts.
* round up to the next 16-vector boundary
*/
#define IRQ0_VECTOR ((FIRST_EXTERNAL_VECTOR + 16) & ~15)
If IRQ0_VECTOR is a legacy ISA interrupt, then it's 0x30. So what's with the rounding? In any case, I don't actually know which vector irq 18 uses, and I don't know how to dump that information out of /proc or /sys.
In any case, I won't fix this unless you and/or the rest of the x86 maintainers tell me you prefer this patch to the one that adds a vsyscall boot parameter.
--Andy
PATCH 2/4 x86: Remove unnecessary compile flag tweaks for vsyscall code
In reply to Andy LutomirskiAs 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
@@ -16,9 +16,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
PATCH 3/4 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.
--- 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
PATCH 4/4 Add vsyscalls to feature-removal-schedule.txt
In reply to Andy LutomirskiIn a couple years, we'll see how well we've done at eradicating vsyscall-using binaries. Hopefully we can then disable them by default. We will probably have to leave the option to enable them around forever.
--- Documentation/feature-removal-schedule.txt | 14 ++++++++++++++ 1 files changed, 14 insertions(+), 0 deletions(-)
Documentation/feature-removal-schedule.txt +14 -0
@@ -575,6 +575,20 @@ Who: Hans Verkuil <[email protected]> ---------------------------- +What: vsyscalls may go away by default +When: 3.6 +Why: All vsyscall functionality is available as regular syscalls and through + the vDSO. Vsyscalls are currently emulated and are slower than normal + syscalls. Userspace exploits can still use the emulated vsyscall traps + as a form of 'ret' instruction. + + In the mean time, do *not* rely on the semantics of int 0x40, int 0x41, + and int 0x42. They may change or go away completely with no notice. + Any attempt to use them will result in a warning in the kernel log. +Who: Andy Lutomirski <[email protected]> + +---------------------------- + What: g_file_storage driver When: 3.8 Why: This driver has been superseded by g_mass_storage.
Signature · 1 line
1.7.6
NACK! Re: [PATCH 4/4] Add vsyscalls to feature-removal-schedule.txt
Quoted 3 lines · Andy Lutomirski
In a couple years, we'll see how well we've done at eradicating vsyscall-using binaries. Hopefully we can then disable them by default. We will probably have to leave the option to enable them around forever.
NACK NACK NACK!
this would break all old (old = meaning all today's) x86-64 installations.
Sorry but I don't think feature removal should be ever for anything commonly used, especially not for anything used by nearly EVERY binary on an old installation. We usually use it for obscure things used rarely.
Repeat after me: BINARY COMPATIBILITY is important. It's not a joke. It's not a toy. It's one of the basic values of Linux.
Sorry to be honest I don't know how you can even suggest such a thing with a straight face.
-Andi
Signature · 1 line
[email protected] -- Speaking for myself only
Re: NACK! Re: [PATCH 4/4] Add vsyscalls to feature-removal-schedule.txt
Quoted 8 lines · Andi Kleen
Quoted 3 lines · Andy Lutomirski
In a couple years, we'll see how well we've done at eradicating vsyscall-using binaries. Hopefully we can then disable them by default. We will probably have to leave the option to enable them around forever.
NACK NACK NACK!
It's already dropped from the version in tip/x86/vdso.
Quoted 1 line
this would break all old (old = meaning all today's) x86-64 installations.
Somewhat to my surprise, fully up-to-date Fedora 15 seems to work fine with vsyscall=none, and I wouldn't be terribly surprised if a few of the distributions starting making it the default sooner or later. I might do a followup patch to make the switch betweeen vsyscall=emulate and vsyscall=none work as a sysctl. (Switching from native to emulate at runtime could be problematic.)
--Andy
Re: NACK! Re: [PATCH 4/4] Add vsyscalls to feature-removal-schedule.txt
Quoted 6 lines · Andrew Lutomirski
Somewhat to my surprise, fully up-to-date Fedora 15 seems to work fine with vsyscall=none, and I wouldn't be terribly surprised if a few of the distributions starting making it the default sooner or later. I might do a followup patch to make the switch betweeen vsyscall=emulate and vsyscall=none work as a sysctl. (Switching from native to emulate at runtime could be problematic.)
As long as no binaries break (emulation is fine) it's perfectly fine to phase out the executable vsyscall page and keep it as a data page only - and we can put that into feature-removal-schedule.txt just fine.
Thanks,
Ingo