x86/vdso fixes for 3.1
Subsystems (6)
Hi Linus,
This is the collected set of vdso fixes, including the change to using "real code protected by NX" for vsyscall=emulate.
This leaves vsyscall=emulate as the default (since we think it should be "good enough" now); we can change that easily enough if it turns out to be insufficient.
The following changes since commit 322a8b034003c0d46d39af85bf24fee27b902f48:
Linux 3.1-rc1 (2011-08-07 18:23:30 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-tip.git x86-vdso-for-linus
Andy Lutomirski (9):
x86-64: Pad vDSO to a page boundary
x86-64: Move the "user" vsyscall segment out of the data segment.
x86-64: Work around gold bug 13023
x86-64, xen: Enable the vvar mapping
x86-64: Add user_64bit_mode paravirt op
x86-64: Add vsyscall:emulate_vsyscall trace event
x86: Remove unnecessary compile flag tweaks for vsyscall code
x86-64: Wire up getcpu syscall
x86-64: Rework vsyscall emulation and add vsyscall= parameter
H. Peter Anvin (1):
Merge commit 'v3.0' into x86/vdso
Documentation/ABI/stable/vdso | 27 +++ Documentation/kernel-parameters.txt | 21 ++ Documentation/vDSO/parse_vdso.c | 256 ++++++++++++++++++++++++ Documentation/vDSO/vdso_test.c | 111 +++++++++++ Documentation/x86/entry_64.txt | 98 +++++++++ arch/ia64/Kconfig | 3 + arch/ia64/include/asm/clocksource.h | 10 + arch/ia64/kernel/cyclone.c | 2 +- arch/ia64/kernel/time.c | 2 +- arch/ia64/sn/kernel/sn2/timer.c | 2 +- arch/x86/Kconfig | 4 + arch/x86/include/asm/alternative-asm.h | 4 +- arch/x86/include/asm/alternative.h | 8 +- arch/x86/include/asm/clocksource.h | 18 ++ arch/x86/include/asm/cpufeature.h | 8 +- arch/x86/include/asm/desc.h | 4 +- arch/x86/include/asm/fixmap.h | 1 + arch/x86/include/asm/irq_vectors.h | 2 +- arch/x86/include/asm/paravirt_types.h | 6 + arch/x86/include/asm/pgtable_types.h | 6 +- arch/x86/include/asm/ptrace.h | 19 ++ arch/x86/include/asm/traps.h | 2 + arch/x86/include/asm/tsc.h | 4 - arch/x86/include/asm/unistd_64.h | 2 + arch/x86/include/asm/vgtod.h | 3 +- arch/x86/include/asm/vsyscall.h | 10 +- arch/x86/include/asm/vvar.h | 24 +-- arch/x86/kernel/Makefile | 21 +-- arch/x86/kernel/alternative.c | 23 +-- arch/x86/kernel/entry_64.S | 3 + arch/x86/kernel/hpet.c | 11 +- arch/x86/kernel/paravirt.c | 4 + arch/x86/kernel/step.c | 2 +- arch/x86/kernel/tsc.c | 2 +- arch/x86/kernel/vmlinux.lds.S | 56 ++---- arch/x86/kernel/vread_tsc_64.c | 36 ---- arch/x86/kernel/vsyscall_64.c | 340 +++++++++++++++---------------- arch/x86/kernel/vsyscall_emu_64.S | 37 ++++ arch/x86/kernel/vsyscall_trace.h | 29 +++ arch/x86/lib/copy_page_64.S | 9 +- arch/x86/lib/memmove_64.S | 11 +- arch/x86/mm/fault.c | 14 ++- arch/x86/vdso/Makefile | 1 + arch/x86/vdso/vclock_gettime.c | 103 ++++++---- arch/x86/vdso/vdso.S | 16 ++- arch/x86/vdso/vma.c | 58 ++++-- arch/x86/xen/enlighten.c | 4 + arch/x86/xen/mmu.c | 4 +- drivers/char/hpet.c | 2 +- include/linux/clocksource.h | 15 +- include/linux/seccomp.h | 10 + 51 files changed, 1048 insertions(+), 420 deletions(-) create mode 100644 Documentation/ABI/stable/vdso create mode 100644 Documentation/vDSO/parse_vdso.c create mode 100644 Documentation/vDSO/vdso_test.c create mode 100644 Documentation/x86/entry_64.txt create mode 100644 arch/ia64/include/asm/clocksource.h create mode 100644 arch/x86/include/asm/clocksource.h delete mode 100644 arch/x86/kernel/vread_tsc_64.c create mode 100644 arch/x86/kernel/vsyscall_emu_64.S create mode 100644 arch/x86/kernel/vsyscall_trace.h
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/desc.h +2 -2
@@ -27,8 +27,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in desc->base2 = (info->base_addr &0xff000000 ) >>24 ;/* -* Don't allow setting of the lm bit. It is useless anyway -* because 64bit system calls require __USER_CS: +* Don't allow setting of the lm bit. It would confuse +* user_64bit_mode and would get overridden by sysret anyway. */ desc->l =0 ; }
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/paravirt_types.h +6 -0
@@ -41,6 +41,7 @@#include <asm/desc_defs.h> #include <asm/kmap_types.h> +#include <asm/pgtable_types.h> struct page ;struct thread_struct ;
@@ -63,6 +64,11 @@ struct paravirt_callee_save {struct pv_info {unsigned int kernel_rpl;int shared_kernel_pmd; + +#ifdef CONFIG_X86_64 +u16 extra_user_64bit_cs;/* __USER_CS if none */ +#endif +int paravirt_enabled;const char *name; };
arch/x86/include/asm/ptrace.h +19 -0
@@ -131,6 +131,9 @@ struct pt_regs {#ifdef __KERNEL__#include <linux/init.h> +#ifdef CONFIG_PARAVIRT +#include <asm/paravirt_types.h> +#endif struct cpuinfo_x86 ;struct task_struct ;
@@ -187,6 +190,22 @@ static inline int v8086_mode(struct pt_regs *regs)#endif } +#ifdef CONFIG_X86_64 +static inline bool user_64bit_mode (struct pt_regs *regs) +{ +#ifndef CONFIG_PARAVIRT +/* +* On non-paravirt systems, this is the only long mode CPL 3 +* selector. We do not allow long mode selectors in the LDT. +*/ +return regs->cs == __USER_CS; +#else +/* Headers are too twisted for this to go in paravirt.h. */ +return regs->cs == __USER_CS || regs->cs == pv_info.extra_user_64bit_cs; +#endif +} +#endif +/* * X86_32 CPUs don't save ss and esp if the CPU is already in kernel mode * when it traps. The previous stack will be directly underneath the saved
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/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
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/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/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/paravirt.c +4 -0
@@ -307,6 +307,10 @@ struct pv_info pv_info = { .paravirt_enabled = 0, .kernel_rpl = 0, .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */ + +#ifdef CONFIG_X86_64 + .extra_user_64bit_cs = __USER_CS, +#endif };struct pv_init_ops pv_init_ops = {
arch/x86/kernel/step.c +1 -1
@@ -74,7 +74,7 @@ static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)#ifdef CONFIG_X86_64 case 0x40 ... 0x4f: -if (regs->cs != __USER_CS) +if (!user_64bit_mode (regs))/* 32-bit mode: register increment */ return 0 ;/* 64-bit mode: REX prefix */
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 +6 -35
57 lines not on this page · raw message
arch/x86/kernel/vsyscall_64.c +54 -36
156 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/kernel/vsyscall_trace.h new file +29 -0
@@ -0,0 +1,29 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM vsyscall + +#if !defined(__VSYSCALL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ ) +#define __VSYSCALL_TRACE_H + +#include <linux/tracepoint.h> + +TRACE_EVENT (emulate_vsyscall, + + TP_PROTO(int nr), + +TP_ARGS (nr), + +TP_STRUCT__entry (__field (int, nr)), + +TP_fast_assign ( + __entry->nr = nr; + ), + +TP_printk ("nr = %d" , __entry->nr) +); + +#endif + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../arch/x86/kernel +#define TRACE_INCLUDE_FILE vsyscall_trace +#include <trace/define_trace.h>
arch/x86/mm/fault.c +13 -1
@@ -105,7 +105,7 @@ check_prefetch_opcode(struct pt_regs *regs, unsigned char *instr,* but for now it's good enough to assume that long * mode only uses well known segments or kernel. */ -return (!user_mode (regs)) || (regs->cs == __USER_CS); +return (!user_mode (regs) ||user_64bit_mode (regs));#endif case 0x60 :/* 0x64 thru 0x67 are valid prefixes in all modes. */
@@ -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);
arch/x86/vdso/vdso.S +1 -0
@@ -9,6 +9,7 @@ __PAGE_ALIGNED_DATA vdso_start: .incbin "arch/x86/vdso/vdso.so" vdso_end: + .align PAGE_SIZE /* extra data here leaks to userspace. */ .previous
arch/x86/xen/enlighten.c +4 -0
@@ -951,6 +951,10 @@ static const struct pv_info xen_info __initconst = { .paravirt_enabled = 1, .shared_kernel_pmd = 0, +#ifdef CONFIG_X86_64 + .extra_user_64bit_cs = FLAT_USER_CS64, +#endif + .name = "Xen", };
arch/x86/xen/mmu.c +3 -1
@@ -1916,6 +1916,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)# endif #else case VSYSCALL_LAST_PAGE ... VSYSCALL_FIRST_PAGE: +case VVAR_PAGE :#endif case FIX_TEXT_POKE0 :case FIX_TEXT_POKE1 :
@@ -1956,7 +1957,8 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)#ifdef CONFIG_X86_64 /* Replicate changes to map the vsyscall page into the user pagetable vsyscall mapping. */ -if (idx >=VSYSCALL_LAST_PAGE && idx <=VSYSCALL_FIRST_PAGE ) { +if ((idx >=VSYSCALL_LAST_PAGE && idx <=VSYSCALL_FIRST_PAGE ) || + idx ==VVAR_PAGE ) {unsigned long vaddr =__fix_to_virt (idx);set_pte_vaddr_pud (level3_user_vsyscall, vaddr, pte); }