aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/vdso.h18
-rw-r--r--arch/x86/vdso/vdso-layout.lds.S44
-rw-r--r--arch/x86/vdso/vdso2c.c12
-rw-r--r--arch/x86/vdso/vdso2c.h25
-rw-r--r--arch/x86/vdso/vma.c20
5 files changed, 62 insertions, 57 deletions
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 30be253dd283..8021bd28c0f1 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -18,15 +18,15 @@ struct vdso_image {
18 18
19 unsigned long alt, alt_len; 19 unsigned long alt, alt_len;
20 20
21 unsigned long sym_end_mapping; /* Total size of the mapping */ 21 long sym_vvar_start; /* Negative offset to the vvar area */
22 22
23 unsigned long sym_vvar_page; 23 long sym_vvar_page;
24 unsigned long sym_hpet_page; 24 long sym_hpet_page;
25 unsigned long sym_VDSO32_NOTE_MASK; 25 long sym_VDSO32_NOTE_MASK;
26 unsigned long sym___kernel_sigreturn; 26 long sym___kernel_sigreturn;
27 unsigned long sym___kernel_rt_sigreturn; 27 long sym___kernel_rt_sigreturn;
28 unsigned long sym___kernel_vsyscall; 28 long sym___kernel_vsyscall;
29 unsigned long sym_VDSO32_SYSENTER_RETURN; 29 long sym_VDSO32_SYSENTER_RETURN;
30}; 30};
31 31
32#ifdef CONFIG_X86_64 32#ifdef CONFIG_X86_64
diff --git a/arch/x86/vdso/vdso-layout.lds.S b/arch/x86/vdso/vdso-layout.lds.S
index 9197544eea9a..de2c921025f5 100644
--- a/arch/x86/vdso/vdso-layout.lds.S
+++ b/arch/x86/vdso/vdso-layout.lds.S
@@ -18,6 +18,25 @@
18 18
19SECTIONS 19SECTIONS
20{ 20{
21 /*
22 * User/kernel shared data is before the vDSO. This may be a little
23 * uglier than putting it after the vDSO, but it avoids issues with
24 * non-allocatable things that dangle past the end of the PT_LOAD
25 * segment.
26 */
27
28 vvar_start = . - 2 * PAGE_SIZE;
29 vvar_page = vvar_start;
30
31 /* Place all vvars at the offsets in asm/vvar.h. */
32#define EMIT_VVAR(name, offset) vvar_ ## name = vvar_page + offset;
33#define __VVAR_KERNEL_LDS
34#include <asm/vvar.h>
35#undef __VVAR_KERNEL_LDS
36#undef EMIT_VVAR
37
38 hpet_page = vvar_start + PAGE_SIZE;
39
21 . = SIZEOF_HEADERS; 40 . = SIZEOF_HEADERS;
22 41
23 .hash : { *(.hash) } :text 42 .hash : { *(.hash) } :text
@@ -74,31 +93,6 @@ SECTIONS
74 .altinstructions : { *(.altinstructions) } :text 93 .altinstructions : { *(.altinstructions) } :text
75 .altinstr_replacement : { *(.altinstr_replacement) } :text 94 .altinstr_replacement : { *(.altinstr_replacement) } :text
76 95
77 /*
78 * The remainder of the vDSO consists of special pages that are
79 * shared between the kernel and userspace. It needs to be at the
80 * end so that it doesn't overlap the mapping of the actual
81 * vDSO image.
82 */
83
84 . = ALIGN(PAGE_SIZE);
85 vvar_page = .;
86
87 /* Place all vvars at the offsets in asm/vvar.h. */
88#define EMIT_VVAR(name, offset) vvar_ ## name = vvar_page + offset;
89#define __VVAR_KERNEL_LDS
90#include <asm/vvar.h>
91#undef __VVAR_KERNEL_LDS
92#undef EMIT_VVAR
93
94 . = vvar_page + PAGE_SIZE;
95
96 hpet_page = .;
97 . = . + PAGE_SIZE;
98
99 . = ALIGN(PAGE_SIZE);
100 end_mapping = .;
101
102 /DISCARD/ : { 96 /DISCARD/ : {
103 *(.discard) 97 *(.discard)
104 *(.discard.*) 98 *(.discard.*)
diff --git a/arch/x86/vdso/vdso2c.c b/arch/x86/vdso/vdso2c.c
index 238dbe82776e..22c54d04bced 100644
--- a/arch/x86/vdso/vdso2c.c
+++ b/arch/x86/vdso/vdso2c.c
@@ -20,9 +20,9 @@ const char *outfilename;
20 20
21/* Symbols that we need in vdso2c. */ 21/* Symbols that we need in vdso2c. */
22enum { 22enum {
23 sym_vvar_start,
23 sym_vvar_page, 24 sym_vvar_page,
24 sym_hpet_page, 25 sym_hpet_page,
25 sym_end_mapping,
26 sym_VDSO_FAKE_SECTION_TABLE_START, 26 sym_VDSO_FAKE_SECTION_TABLE_START,
27 sym_VDSO_FAKE_SECTION_TABLE_END, 27 sym_VDSO_FAKE_SECTION_TABLE_END,
28}; 28};
@@ -38,9 +38,9 @@ struct vdso_sym {
38}; 38};
39 39
40struct vdso_sym required_syms[] = { 40struct vdso_sym required_syms[] = {
41 [sym_vvar_start] = {"vvar_start", true},
41 [sym_vvar_page] = {"vvar_page", true}, 42 [sym_vvar_page] = {"vvar_page", true},
42 [sym_hpet_page] = {"hpet_page", true}, 43 [sym_hpet_page] = {"hpet_page", true},
43 [sym_end_mapping] = {"end_mapping", true},
44 [sym_VDSO_FAKE_SECTION_TABLE_START] = { 44 [sym_VDSO_FAKE_SECTION_TABLE_START] = {
45 "VDSO_FAKE_SECTION_TABLE_START", false 45 "VDSO_FAKE_SECTION_TABLE_START", false
46 }, 46 },
@@ -96,9 +96,11 @@ extern void bad_put_le(void);
96 96
97#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0])) 97#define NSYMS (sizeof(required_syms) / sizeof(required_syms[0]))
98 98
99#define BITSFUNC3(name, bits) name##bits 99#define BITSFUNC3(name, bits, suffix) name##bits##suffix
100#define BITSFUNC2(name, bits) BITSFUNC3(name, bits) 100#define BITSFUNC2(name, bits, suffix) BITSFUNC3(name, bits, suffix)
101#define BITSFUNC(name) BITSFUNC2(name, ELF_BITS) 101#define BITSFUNC(name) BITSFUNC2(name, ELF_BITS, )
102
103#define INT_BITS BITSFUNC2(int, ELF_BITS, _t)
102 104
103#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x 105#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
104#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x) 106#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
diff --git a/arch/x86/vdso/vdso2c.h b/arch/x86/vdso/vdso2c.h
index 11b65d4f9414..2da32fbc46da 100644
--- a/arch/x86/vdso/vdso2c.h
+++ b/arch/x86/vdso/vdso2c.h
@@ -132,7 +132,7 @@ static void BITSFUNC(go)(void *addr, size_t len,
132 *alt_sec = NULL; 132 *alt_sec = NULL;
133 ELF(Dyn) *dyn = 0, *dyn_end = 0; 133 ELF(Dyn) *dyn = 0, *dyn_end = 0;
134 const char *secstrings; 134 const char *secstrings;
135 uint64_t syms[NSYMS] = {}; 135 INT_BITS syms[NSYMS] = {};
136 136
137 struct BITSFUNC(fake_sections) fake_sections = {}; 137 struct BITSFUNC(fake_sections) fake_sections = {};
138 138
@@ -209,6 +209,13 @@ static void BITSFUNC(go)(void *addr, size_t len,
209 fail("duplicate symbol %s\n", 209 fail("duplicate symbol %s\n",
210 required_syms[k].name); 210 required_syms[k].name);
211 } 211 }
212
213 /*
214 * Careful: we use negative addresses, but
215 * st_value is unsigned, so we rely
216 * on syms[k] being a signed type of the
217 * correct width.
218 */
212 syms[k] = GET_LE(&sym->st_value); 219 syms[k] = GET_LE(&sym->st_value);
213 } 220 }
214 } 221 }
@@ -263,15 +270,15 @@ static void BITSFUNC(go)(void *addr, size_t len,
263 if (syms[i] % 4096) 270 if (syms[i] % 4096)
264 fail("%s must be a multiple of 4096\n", 271 fail("%s must be a multiple of 4096\n",
265 required_syms[i].name); 272 required_syms[i].name);
266 if (syms[i] < data_size) 273 if (syms[sym_vvar_start] > syms[i] + 4096)
267 fail("%s must be after the text mapping\n", 274 fail("%s underruns begin_vvar\n",
268 required_syms[i].name); 275 required_syms[i].name);
269 if (syms[sym_end_mapping] < syms[i] + 4096) 276 if (syms[i] + 4096 > 0)
270 fail("%s overruns end_mapping\n", 277 fail("%s is on the wrong side of the vdso text\n",
271 required_syms[i].name); 278 required_syms[i].name);
272 } 279 }
273 if (syms[sym_end_mapping] % 4096) 280 if (syms[sym_vvar_start] % 4096)
274 fail("end_mapping must be a multiple of 4096\n"); 281 fail("vvar_begin must be a multiple of 4096\n");
275 282
276 if (!name) {