aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-i386
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2006-06-27 05:53:50 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-27 20:32:38 -0400
commite6e5494cb23d1933735ee47cc674ffe1c4afed6f (patch)
treec8945bb3ae5bec38693d801fb589d22d48d6f8eb /include/asm-i386
parentd5fb34261dcd32c9cb3b28121fdc46308db513a1 (diff)
[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>
Diffstat (limited to 'include/asm-i386')
-rw-r--r--include/asm-i386/elf.h53
-rw-r--r--include/asm-i386/fixmap.h10
-rw-r--r--include/asm-i386/mmu.h1
-rw-r--r--include/asm-i386/page.h3
-rw-r--r--include/asm-i386/thread_info.h1
-rw-r--r--include/asm-i386/unwind.h4
6 files changed, 48 insertions, 24 deletions
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index 4153d80e4d2b..1eac92cb5b16 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -10,6 +10,7 @@
10#include <asm/processor.h> 10#include <asm/processor.h>
11#include <asm/system.h> /* for savesegment */ 11#include <asm/system.h> /* for savesegment */
12#include <asm/auxvec.h> 12#include <asm/auxvec.h>
13#include <asm/desc.h>
13 14
14#include <linux/utsname.h> 15#include <linux/utsname.h>
15 16
@@ -129,15 +130,41 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct
129#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) 130#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
130#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs) 131#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
131 132
132#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) 133#define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO))
133#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) 134#define VDSO_BASE ((unsigned long)current->mm->context.vdso)
134#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) 135
136#ifdef CONFIG_COMPAT_VDSO
137# define VDSO_COMPAT_BASE VDSO_HIGH_BASE
138# define VDSO_PRELINK VDSO_HIGH_BASE
139#else
140# define VDSO_COMPAT_BASE VDSO_BASE
141# define VDSO_PRELINK 0
142#endif
143
144#define VDSO_COMPAT_SYM(x) \
145 (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
146
147#define VDSO_SYM(x) \
148 (VDSO_BASE + (unsigned long)(x) - VDSO_PRELINK)
149
150#define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE)
151#define VDSO_EHDR ((const struct elfhdr *) VDSO_COMPAT_BASE)
152
135extern void __kernel_vsyscall; 153extern void __kernel_vsyscall;
136 154
155#define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall)
156
157#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
158struct linux_binprm;
159extern int arch_setup_additional_pages(struct linux_binprm *bprm,
160 int executable_stack);
161
162extern unsigned int vdso_enabled;
163
137#define ARCH_DLINFO \ 164#define ARCH_DLINFO \
138do { \ 165do if (vdso_enabled) { \
139 NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ 166 NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
140 NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ 167 NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
141} while (0) 168} while (0)
142 169
143/* 170/*
@@ -148,15 +175,15 @@ do { \
148 * Dumping its extra ELF program headers includes all the other information 175 * Dumping its extra ELF program headers includes all the other information
149 * a debugger needs to easily find how the vsyscall DSO was being used. 176 * a debugger needs to easily find how the vsyscall DSO was being used.
150 */ 177 */
151#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) 178#define ELF_CORE_EXTRA_PHDRS (VDSO_HIGH_EHDR->e_phnum)
152#define ELF_CORE_WRITE_EXTRA_PHDRS \ 179#define ELF_CORE_WRITE_EXTRA_PHDRS \
153do { \ 180do { \
154 const struct elf_phdr *const vsyscall_phdrs = \ 181 const struct elf_phdr *const vsyscall_phdrs = \
155 (const struct elf_phdr *) (VSYSCALL_BASE \ 182 (const struct elf_phdr *) (VDSO_HIGH_BASE \
156 + VSYSCALL_EHDR->e_phoff); \ 183 + VDSO_HIGH_EHDR->e_phoff); \
157 int i; \ 184 int i; \
158 Elf32_Off ofs = 0; \ 185 Elf32_Off ofs = 0; \
159 for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ 186 for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
160 struct elf_phdr phdr = vsyscall_phdrs[i]; \ 187 struct elf_phdr phdr = vsyscall_phdrs[i]; \
161 if (phdr.p_type == PT_LOAD) { \ 188 if (phdr.p_type == PT_LOAD) { \
162 BUG_ON(ofs != 0); \ 189 BUG_ON(ofs != 0); \
@@ -174,10 +201,10 @@ do { \
174#define ELF_CORE_WRITE_EXTRA_DATA \ 201#define ELF_CORE_WRITE_EXTRA_DATA \
175do { \ 202do { \
176 const struct elf_phdr *const vsyscall_phdrs = \ 203 const struct elf_phdr *const vsyscall_phdrs = \
177 (const struct elf_phdr *) (VSYSCALL_BASE \ 204 (const struct elf_phdr *) (VDSO_HIGH_BASE \
178 + VSYSCALL_EHDR->e_phoff); \ 205 + VDSO_HIGH_EHDR->e_phoff); \
179 int i; \ 206 int i; \
180 for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ 207 for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) { \
181 if (vsyscall_phdrs[i].p_type == PT_LOAD) \ 208 if (vsyscall_phdrs[i].p_type == PT_LOAD) \
182 DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \ 209 DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \
183 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \ 210 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz)); \
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index f7e068f4d2f9..a48cc3f7ccc6 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -51,7 +51,7 @@
51 */ 51 */
52enum fixed_addresses { 52enum fixed_addresses {
53 FIX_HOLE, 53 FIX_HOLE,
54 FIX_VSYSCALL, 54 FIX_VDSO,
55#ifdef CONFIG_X86_LOCAL_APIC 55#ifdef CONFIG_X86_LOCAL_APIC
56 FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */ 56 FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
57#endif 57#endif
@@ -115,14 +115,6 @@ extern void __set_fixmap (enum fixed_addresses idx,
115#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) 115#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
116#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) 116#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
117 117
118/*
119 * This is the range that is readable by user mode, and things
120 * acting like user mode such as get_user_pages.
121 */
122#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL))
123#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE)
124
125
126extern void __this_fixmap_does_not_exist(void); 118extern void __this_fixmap_does_not_exist(void);
127 119
128/* 120/*
diff --git a/include/asm-i386/mmu.h b/include/asm-i386/mmu.h
index f431a0b86d4c..8358dd3df7aa 100644
--- a/include/asm-i386/mmu.h
+++ b/include/asm-i386/mmu.h
@@ -12,6 +12,7 @@ typedef struct {
12 int size; 12 int size;
13 struct semaphore sem; 13 struct semaphore sem;
14 void *ldt; 14 void *ldt;
15 void *vdso;
15} mm_context_t; 16} mm_context_t;
16 17
17#endif 18#endif
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index e3a552fa5538..f5bf544c729a 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -96,6 +96,8 @@ typedef struct { unsigned long pgprot; } pgprot_t;
96 96
97#ifndef __ASSEMBLY__ 97#ifndef __ASSEMBLY__
98 98
99struct vm_area_struct;
100
99/* 101/*
100 * This much address space is reserved for vmalloc() and iomap() 102 * This much address space is reserved for vmalloc() and iomap()
101 * as well as fixmap mappings. 103 * as well as fixmap mappings.
@@ -139,6 +141,7 @@ extern int page_is_ram(unsigned long pagenr);
139#include <asm-generic/memory_model.h> 141#include <asm-generic/memory_model.h>
140#include <asm-generic/page.h> 142#include <asm-generic/page.h>
141 143
144#define __HAVE_ARCH_GATE_AREA 1
142#endif /* __KERNEL__ */ 145#endif /* __KERNEL__ */
143 146
144#endif /* _I386_PAGE_H */ 147#endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index ff1e2b1a7c84..2833fa2c0dd0 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -37,6 +37,7 @@ struct thread_info {
37 0-0xBFFFFFFF for user-thead 37 0-0xBFFFFFFF for user-thead
38 0-0xFFFFFFFF for kernel-thread 38 0-0xFFFFFFFF for kernel-thread
39 */ 39 */
40 void *sysenter_return;
40 struct restart_block restart_block; 41 struct restart_block restart_block;
41 42
42 unsigned long previous_esp; /* ESP of the previous stack in case 43 unsigned long previous_esp; /* ESP of the previous stack in case
diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h
index d480f2e38215..69f0f1df6722 100644
--- a/include/asm-i386/unwind.h
+++ b/include/asm-i386/unwind.h
@@ -78,8 +78,8 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
78 return user_mode_vm(&info->regs); 78 return user_mode_vm(&info->regs);
79#else 79#else
80 return info->regs.eip < PAGE_OFFSET 80 return info->regs.eip < PAGE_OFFSET
81 || (info->regs.eip >= __fix_to_virt(FIX_VSYSCALL) 81 || (info->regs.eip >= __fix_to_virt(FIX_VDSO)
82 && info->regs.eip < __fix_to_virt(FIX_VSYSCALL) + PAGE_SIZE) 82 && info->regs.eip < __fix_to_virt(FIX_VDSO) + PAGE_SIZE)
83 || info->regs.esp < PAGE_OFFSET; 83 || info->regs.esp < PAGE_OFFSET;
84#endif 84#endif
85} 85}