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) { 283 if (!name) {
277 fwrite(addr, load_size, 1, outfile); 284 fwrite(addr, load_size, 1, outfile);
@@ -311,8 +318,8 @@ static void BITSFUNC(go)(void *addr, size_t len,
311 } 318 }
312 for (i = 0; i < NSYMS; i++) { 319 for (i = 0; i < NSYMS; i++) {
313 if (required_syms[i].export && syms[i]) 320 if (required_syms[i].export && syms[i])
314 fprintf(outfile, "\t.sym_%s = 0x%" PRIx64 ",\n", 321 fprintf(outfile, "\t.sym_%s = %" PRIi64 ",\n",
315 required_syms[i].name, syms[i]); 322 required_syms[i].name, (int64_t)syms[i]);
316 } 323 }
317 fprintf(outfile, "};\n"); 324 fprintf(outfile, "};\n");
318} 325}
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 5a5176de8d0a..dbef622bb5af 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -93,7 +93,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
93{ 93{
94 struct mm_struct *mm = current->mm; 94 struct mm_struct *mm = current->mm;
95 struct vm_area_struct *vma; 95 struct vm_area_struct *vma;
96 unsigned long addr; 96 unsigned long addr, text_start;
97 int ret = 0; 97 int ret = 0;
98 static struct page *no_pages[] = {NULL}; 98 static struct page *no_pages[] = {NULL};
99 static struct vm_special_mapping vvar_mapping = { 99 static struct vm_special_mapping vvar_mapping = {
@@ -103,26 +103,28 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
103 103
104 if (calculate_addr) { 104 if (calculate_addr) {
105 addr = vdso_addr(current->mm->start_stack, 105 addr = vdso_addr(current->mm->start_stack,
106 image->sym_end_mapping); 106 image->size - image->sym_vvar_start);
107 } else { 107 } else {
108 addr = 0; 108 addr = 0;
109 } 109 }
110 110
111 down_write(&mm->mmap_sem); 111 down_write(&mm->mmap_sem);
112 112
113 addr = get_unmapped_area(NULL, addr, image->sym_end_mapping, 0, 0); 113 addr = get_unmapped_area(NULL, addr,
114 image->size - image->sym_vvar_start, 0, 0);
114 if (IS_ERR_VALUE(addr)) { 115 if (IS_ERR_VALUE(addr)) {
115 ret = addr; 116 ret = addr;
116 goto up_fail; 117 goto up_fail;
117 } 118 }
118 119
119 current->mm->context.vdso = (void __user *)addr; 120 text_start = addr - image->sym_vvar_start;
121 current->mm->context.vdso = (void __user *)text_start;
120 122
121 /* 123 /*
122 * MAYWRITE to allow gdb to COW and set breakpoints 124 * MAYWRITE to allow gdb to COW and set breakpoints
123 */ 125 */
124 vma = _install_special_mapping(mm, 126 vma = _install_special_mapping(mm,
125 addr, 127 text_start,
126 image->size, 128 image->size,
127 VM_READ|VM_EXEC| 129 VM_READ|VM_EXEC|
128 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 130 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
@@ -134,8 +136,8 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
134 } 136 }
135 137
136 vma = _install_special_mapping(mm, 138 vma = _install_special_mapping(mm,
137 addr + image->size, 139 addr,
138 image->sym_end_mapping - image->size, 140 -image->sym_vvar_start,
139 VM_READ, 141 VM_READ,
140 &vvar_mapping); 142 &vvar_mapping);
141 143
@@ -146,7 +148,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
146 148
147 if (image->sym_vvar_page) 149 if (image->sym_vvar_page)
148 ret = remap_pfn_range(vma, 150 ret = remap_pfn_range(vma,
149 addr + image->sym_vvar_page, 151 text_start + image->sym_vvar_page,
150 __pa_symbol(&__vvar_page) >> PAGE_SHIFT, 152 __pa_symbol(&__vvar_page) >> PAGE_SHIFT,
151 PAGE_SIZE, 153 PAGE_SIZE,
152 PAGE_READONLY); 154 PAGE_READONLY);
@@ -157,7 +159,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
157#ifdef CONFIG_HPET_TIMER 159#ifdef CONFIG_HPET_TIMER
158 if (hpet_address && image->sym_hpet_page) { 160 if (hpet_address && image->sym_hpet_page) {
159 ret = io_remap_pfn_range(vma, 161 ret = io_remap_pfn_range(vma,
160 addr + image->sym_hpet_page, 162 text_start + image->sym_hpet_page,
161 hpet_address >> PAGE_SHIFT, 163 hpet_address >> PAGE_SHIFT,
162 PAGE_SIZE, 164 PAGE_SIZE,
163 pgprot_noncached(PAGE_READONLY)); 165 pgprot_noncached(PAGE_READONLY));