Commit 5cec93c2 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Ingo Molnar

x86-64: Emulate legacy vsyscalls

There's a fair amount of code in the vsyscall page.  It contains
a syscall instruction (in the gettimeofday fallback) and who
knows what will happen if an exploit jumps into the middle of
some other code.

Reduce the risk by replacing the vsyscalls with short magic
incantations that cause the kernel to emulate the real
vsyscalls. These incantations are useless if entered in the
middle.

This causes vsyscalls to be a little more expensive than real
syscalls.  Fortunately sensible programs don't use them.
The only exception is time() which is still called by glibc
through the vsyscall - but calling time() millions of times
per second is not sensible. glibc has this fixed in the
development tree.

This patch is not perfect: the vread_tsc and vread_hpet
functions are still at a fixed address.  Fixing that might
involve making alternative patching work in the vDSO.
Signed-off-by: default avatarAndy Lutomirski <luto@mit.edu>
Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Cc: Jesper Juhl <jj@chaosbits.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Arjan van de Ven <arjan@infradead.org>
Cc: Jan Beulich <JBeulich@novell.com>
Cc: richard -rw- weinberger <richard.weinberger@gmail.com>
Cc: Mikael Pettersson <mikpe@it.uu.se>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Louis Rilling <Louis.Rilling@kerlabs.com>
Cc: Valdis.Kletnieks@vt.edu
Cc: pageexec@freemail.hu
Link: http://lkml.kernel.org/r/e64e1b3c64858820d12c48fa739efbd1485e79d5.1307292171.git.luto@mit.edu
[ Removed the CONFIG option - it's simpler to just do it unconditionally. Tidied up the code as well. ]
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 5dfcea62
...@@ -17,7 +17,8 @@ ...@@ -17,7 +17,8 @@
* Vectors 0 ... 31 : system traps and exceptions - hardcoded events * Vectors 0 ... 31 : system traps and exceptions - hardcoded events
* Vectors 32 ... 127 : device interrupts * Vectors 32 ... 127 : device interrupts
* Vector 128 : legacy int80 syscall interface * Vector 128 : legacy int80 syscall interface
* Vectors 129 ... INVALIDATE_TLB_VECTOR_START-1 : device interrupts * 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 * Vectors INVALIDATE_TLB_VECTOR_START ... 255 : special interrupts
* *
* 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table. * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
...@@ -50,6 +51,9 @@ ...@@ -50,6 +51,9 @@
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
# define SYSCALL_VECTOR 0x80 # define SYSCALL_VECTOR 0x80
#endif #endif
#ifdef CONFIG_X86_64
# define VSYSCALL_EMU_VECTOR 0xcc
#endif
/* /*
* Vectors 0x30-0x3f are used for ISA interrupts. * Vectors 0x30-0x3f are used for ISA interrupts.
......
#ifndef _ASM_X86_TRAPS_H #ifndef _ASM_X86_TRAPS_H
#define _ASM_X86_TRAPS_H #define _ASM_X86_TRAPS_H
#include <linux/kprobes.h>
#include <asm/debugreg.h> #include <asm/debugreg.h>
#include <asm/siginfo.h> /* TRAP_TRACE, ... */ #include <asm/siginfo.h> /* TRAP_TRACE, ... */
...@@ -38,6 +40,7 @@ asmlinkage void alignment_check(void); ...@@ -38,6 +40,7 @@ asmlinkage void alignment_check(void);
asmlinkage void machine_check(void); asmlinkage void machine_check(void);
#endif /* CONFIG_X86_MCE */ #endif /* CONFIG_X86_MCE */
asmlinkage void simd_coprocessor_error(void); asmlinkage void simd_coprocessor_error(void);
asmlinkage void emulate_vsyscall(void);
dotraplinkage void do_divide_error(struct pt_regs *, long); dotraplinkage void do_divide_error(struct pt_regs *, long);
dotraplinkage void do_debug(struct pt_regs *, long); dotraplinkage void do_debug(struct pt_regs *, long);
...@@ -64,6 +67,7 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long); ...@@ -64,6 +67,7 @@ dotraplinkage void do_alignment_check(struct pt_regs *, long);
dotraplinkage void do_machine_check(struct pt_regs *, long); dotraplinkage void do_machine_check(struct pt_regs *, long);
#endif #endif
dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long); dotraplinkage void do_simd_coprocessor_error(struct pt_regs *, long);
dotraplinkage void do_emulate_vsyscall(struct pt_regs *, long);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
dotraplinkage void do_iret_error(struct pt_regs *, long); dotraplinkage void do_iret_error(struct pt_regs *, long);
#endif #endif
......
...@@ -31,6 +31,18 @@ extern struct timezone sys_tz; ...@@ -31,6 +31,18 @@ extern struct timezone sys_tz;
extern void map_vsyscall(void); extern void map_vsyscall(void);
/* Emulation */
static inline bool is_vsyscall_entry(unsigned long addr)
{
return (addr & ~0xC00UL) == VSYSCALL_START;
}
static inline int vsyscall_entry_nr(unsigned long addr)
{
return (addr & 0xC00UL) >> 10;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_X86_VSYSCALL_H */ #endif /* _ASM_X86_VSYSCALL_H */
...@@ -44,6 +44,7 @@ obj-y += probe_roms.o ...@@ -44,6 +44,7 @@ obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o vread_tsc_64.o obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o vread_tsc_64.o
obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
obj-y += bootflag.o e820.o obj-y += bootflag.o e820.o
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
......
...@@ -1123,6 +1123,8 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug ...@@ -1123,6 +1123,8 @@ zeroentry spurious_interrupt_bug do_spurious_interrupt_bug
zeroentry coprocessor_error do_coprocessor_error zeroentry coprocessor_error do_coprocessor_error
errorentry alignment_check do_alignment_check errorentry alignment_check do_alignment_check
zeroentry simd_coprocessor_error do_simd_coprocessor_error zeroentry simd_coprocessor_error do_simd_coprocessor_error
zeroentry emulate_vsyscall do_emulate_vsyscall
/* Reload gs selector with exception handling */ /* Reload gs selector with exception handling */
/* edi: new selector */ /* edi: new selector */
......
...@@ -872,6 +872,12 @@ void __init trap_init(void) ...@@ -872,6 +872,12 @@ void __init trap_init(void)
set_bit(SYSCALL_VECTOR, used_vectors); set_bit(SYSCALL_VECTOR, used_vectors);
#endif #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: * Should be a barrier for any external CPU state:
*/ */
......
This diff is collapsed.
/*
* vsyscall_emu_64.S: Vsyscall emulation page
*
* Copyright (c) 2011 Andy Lutomirski
*
* Subject to the GNU General Public License, version 2
*/
#include <linux/linkage.h>
#include <asm/irq_vectors.h>
/* The unused parts of the page are filled with 0xcc by the linker script. */
.section .vsyscall_0, "a"
ENTRY(vsyscall_0)
int $VSYSCALL_EMU_VECTOR
END(vsyscall_0)
.section .vsyscall_1, "a"
ENTRY(vsyscall_1)
int $VSYSCALL_EMU_VECTOR
END(vsyscall_1)
.section .vsyscall_2, "a"
ENTRY(vsyscall_2)
int $VSYSCALL_EMU_VECTOR
END(vsyscall_2)
...@@ -19,6 +19,11 @@ static inline void secure_computing(int this_syscall) ...@@ -19,6 +19,11 @@ static inline void secure_computing(int this_syscall)
extern long prctl_get_seccomp(void); extern long prctl_get_seccomp(void);
extern long prctl_set_seccomp(unsigned long); extern long prctl_set_seccomp(unsigned long);
static inline int seccomp_mode(seccomp_t *s)
{
return s->mode;
}
#else /* CONFIG_SECCOMP */ #else /* CONFIG_SECCOMP */
#include <linux/errno.h> #include <linux/errno.h>
...@@ -37,6 +42,11 @@ static inline long prctl_set_seccomp(unsigned long arg2) ...@@ -37,6 +42,11 @@ static inline long prctl_set_seccomp(unsigned long arg2)
return -EINVAL; return -EINVAL;
} }
static inline int seccomp_mode(seccomp_t *s)
{
return 0;
}
#endif /* CONFIG_SECCOMP */ #endif /* CONFIG_SECCOMP */
#endif /* _LINUX_SECCOMP_H */ #endif /* _LINUX_SECCOMP_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment