[PATCH] vdso: randomize the i386 vDSO by moving it into a vma
Move the i386 VDSO down into a vma and thus randomize it. Besides the security implications, this feature also helps debuggers, which can COW a vma-backed VDSO just like a normal DSO and can thus do single-stepping and other debugging features. It's good for hypervisors (Xen, VMWare) too, which typically live in the same high-mapped address space as the VDSO, hence whenever the VDSO is used, they get lots of guest pagefaults and have to fix such guest accesses up - which slows things down instead of speeding things up (the primary purpose of the VDSO). There's a new CONFIG_COMPAT_VDSO (default=y) option, which provides support for older glibcs that still rely on a prelinked high-mapped VDSO. Newer distributions (using glibc 2.3.3 or later) can turn this option off. Turning it off is also recommended for security reasons: attackers cannot use the predictable high-mapped VDSO page as syscall trampoline anymore. There is a new vdso=[0|1] boot option as well, and a runtime /proc/sys/vm/vdso_enabled sysctl switch, that allows the VDSO to be turned on/off. (This version of the VDSO-randomization patch also has working ELF coredumping, the previous patch crashed in the coredumping code.) This code is a combined work of the exec-shield VDSO randomization code and Gerd Hoffmann's hypervisor-centric VDSO patch. Rusty Russell started this patch and i completed it. [akpm@osdl.org: cleanups] [akpm@osdl.org: compile fix] [akpm@osdl.org: compile fix 2] [akpm@osdl.org: compile fix 3] [akpm@osdl.org: revernt MAXMEM change] Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Arjan van de Ven <arjan@infradead.org> Cc: Gerd Hoffmann <kraxel@suse.de> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Zachary Amsden <zach@vmware.com> Cc: Andi Kleen <ak@muc.de> Cc: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:

committed by
Linus Torvalds

parent
d5fb34261d
commit
e6e5494cb2
@@ -10,6 +10,7 @@
|
||||
#include <asm/processor.h>
|
||||
#include <asm/system.h> /* for savesegment */
|
||||
#include <asm/auxvec.h>
|
||||
#include <asm/desc.h>
|
||||
|
||||
#include <linux/utsname.h>
|
||||
|
||||
@@ -129,15 +130,41 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct
|
||||
#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
|
||||
#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
|
||||
|
||||
#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL))
|
||||
#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE)
|
||||
#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall)
|
||||
#define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO))
|
||||
#define VDSO_BASE ((unsigned long)current->mm->context.vdso)
|
||||
|
||||
#ifdef CONFIG_COMPAT_VDSO
|
||||
# define VDSO_COMPAT_BASE VDSO_HIGH_BASE
|
||||
# define VDSO_PRELINK VDSO_HIGH_BASE
|
||||
#else
|
||||
# define VDSO_COMPAT_BASE VDSO_BASE
|
||||
# define VDSO_PRELINK 0
|
||||
#endif
|
||||
|
||||
#define VDSO_COMPAT_SYM(x) \
|
||||
(VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
|
||||
|
||||
#define VDSO_SYM(x) \
|
||||
(VDSO_BASE + (unsigned long)(x) - VDSO_PRELINK)
|
||||
|
||||
#define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE)
|
||||
#define VDSO_EHDR ((const struct elfhdr *) VDSO_COMPAT_BASE)
|
||||
|
||||
extern void __kernel_vsyscall;
|
||||
|
||||
#define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall)
|
||||
|
||||
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
|
||||
struct linux_binprm;
|
||||
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
|
||||
int executable_stack);
|
||||
|
||||
extern unsigned int vdso_enabled;
|
||||
|
||||
#define ARCH_DLINFO \
|
||||
do { \
|
||||
NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \
|
||||
NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \
|
||||
do if (vdso_enabled) { \
|
||||
NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
|
||||
NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
@@ -148,15 +175,15 @@ do { \
|
||||
* Dumping its extra ELF program headers includes all the other information
|
||||
* a debugger needs to easily find how the vsyscall DSO was being used.
|
||||
*/
|
||||
#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum)
|
||||
#define ELF_CORE_EXTRA_PHDRS (VDSO_HIGH_EHDR->e_phnum)
|
||||
#define ELF_CORE_WRITE_EXTRA_PHDRS \
|
||||
do { \
|
||||
const struct elf_phdr *const vsyscall_phdrs = \
|
||||
(const struct elf_phdr *) (VSYSCALL_BASE \
|
||||
+ VSYSCALL_EHDR->e_phoff); \
|
||||
(const struct elf_phdr *) (VDSO_HIGH_BASE \
|
||||
+ VDSO_HIGH_EHDR->e_phoff); \
|
||||
int i; \
|
||||
Elf32_Off ofs = 0; \
|
||||
for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \
|
||||
for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
|
||||
struct elf_phdr phdr = vsyscall_phdrs[i]; \
|
||||
if (phdr.p_type == PT_LOAD) { \
|
||||
BUG_ON(ofs != 0); \
|
||||
@@ -174,10 +201,10 @@ do { \
|
||||
#define ELF_CORE_WRITE_EXTRA_DATA \
|
||||
do { \
|
||||
const struct elf_phdr *const vsyscall_phdrs = \
|
||||
(const struct elf_phdr *) (VSYSCALL_BASE \
|
||||
+ VSYSCALL_EHDR->e_phoff); \
|
||||
(const struct elf_phdr *) (VDSO_HIGH_BASE \
|
||||
+ VDSO_HIGH_EHDR->e_phoff); \
|
||||
int i; \
|
||||
for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \
|
||||
for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
|
||||
if (vsyscall_phdrs[i].p_type == PT_LOAD) \
|
||||
DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \
|
||||
PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \
|
||||
|
Reference in New Issue
Block a user