aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2014-07-09 14:22:13 -0400
committerCatalin Marinas <catalin.marinas@arm.com>2014-07-17 11:18:57 -0400
commit601255ae3c98fdeeee3a8bb4696425e4f868b4f1 (patch)
tree02f118302b7d2f01c0ee35a026e406976c23fc73
parent2fea7f6c98f5957e539eb8aa0ce849729b900342 (diff)
arm64: vdso: move data page before code pages
Andy pointed out that binutils generates additional sections in the vdso image (e.g. section string table) which, if our .text section gets big enough, could cross a page boundary and end up screwing up the location where the kernel expects to put the data page. This patch solves the issue in the same manner as x86_32, by moving the data page before the code pages. Cc: Andy Lutomirski <luto@amacapital.net> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r--arch/arm64/kernel/vdso.c34
-rw-r--r--arch/arm64/kernel/vdso/vdso.lds.S4
2 files changed, 18 insertions, 20 deletions
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 60ae12087d9f..24f2e8c62479 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -121,8 +121,8 @@ static int __init vdso_init(void)
121 } 121 }
122 122
123 vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT; 123 vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
124 pr_info("vdso: %ld pages (%ld code, %ld data) at base %p\n", 124 pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
125 vdso_pages + 1, vdso_pages, 1L, &vdso_start); 125 vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
126 126
127 /* Allocate the vDSO pagelist, plus a page for the data. */ 127 /* Allocate the vDSO pagelist, plus a page for the data. */
128 vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *), 128 vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
@@ -130,22 +130,22 @@ static int __init vdso_init(void)
130 if (vdso_pagelist == NULL) 130 if (vdso_pagelist == NULL)
131 return -ENOMEM; 131 return -ENOMEM;
132 132
133 /* Grab the vDSO data page. */
134 vdso_pagelist[0] = virt_to_page(vdso_data);
135
133 /* Grab the vDSO code pages. */ 136 /* Grab the vDSO code pages. */
134 for (i = 0; i < vdso_pages; i++) 137 for (i = 0; i < vdso_pages; i++)
135 vdso_pagelist[i] = virt_to_page(&vdso_start + i * PAGE_SIZE); 138 vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE);
136
137 /* Grab the vDSO data page. */
138 vdso_pagelist[i] = virt_to_page(vdso_data);
139 139
140 /* Populate the special mapping structures */ 140 /* Populate the special mapping structures */
141 vdso_spec[0] = (struct vm_special_mapping) { 141 vdso_spec[0] = (struct vm_special_mapping) {
142 .name = "[vdso]", 142 .name = "[vvar]",
143 .pages = vdso_pagelist, 143 .pages = vdso_pagelist,
144 }; 144 };
145 145
146 vdso_spec[1] = (struct vm_special_mapping) { 146 vdso_spec[1] = (struct vm_special_mapping) {
147 .name = "[vvar]", 147 .name = "[vdso]",
148 .pages = vdso_pagelist + vdso_pages, 148 .pages = &vdso_pagelist[1],
149 }; 149 };
150 150
151 return 0; 151 return 0;
@@ -169,22 +169,22 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
169 ret = ERR_PTR(vdso_base); 169 ret = ERR_PTR(vdso_base);
170 goto up_fail; 170 goto up_fail;
171 } 171 }
172 mm->context.vdso = (void *)vdso_base; 172 ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
173 173 VM_READ|VM_MAYREAD,
174 ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
175 VM_READ|VM_EXEC|
176 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
177 &vdso_spec[0]); 174 &vdso_spec[0]);
178 if (IS_ERR(ret)) 175 if (IS_ERR(ret))
179 goto up_fail; 176 goto up_fail;
180 177
181 vdso_base += vdso_text_len; 178 vdso_base += PAGE_SIZE;
182 ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE, 179 mm->context.vdso = (void *)vdso_base;
183 VM_READ|VM_MAYREAD, 180 ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
181 VM_READ|VM_EXEC|
182 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
184 &vdso_spec[1]); 183 &vdso_spec[1]);
185 if (IS_ERR(ret)) 184 if (IS_ERR(ret))
186 goto up_fail; 185 goto up_fail;
187 186
187
188 up_write(&mm->mmap_sem); 188 up_write(&mm->mmap_sem);
189 return 0; 189 return 0;
190 190
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 8154b8d1c826..beca249bc2f3 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -28,6 +28,7 @@ OUTPUT_ARCH(aarch64)
28 28
29SECTIONS 29SECTIONS
30{ 30{
31 PROVIDE(_vdso_data = . - PAGE_SIZE);
31 . = VDSO_LBASE + SIZEOF_HEADERS; 32 . = VDSO_LBASE + SIZEOF_HEADERS;
32 33
33 .hash : { *(.hash) } :text 34 .hash : { *(.hash) } :text
@@ -57,9 +58,6 @@ SECTIONS
57 _end = .; 58 _end = .;
58 PROVIDE(end = .); 59 PROVIDE(end = .);
59 60
60 . = ALIGN(PAGE_SIZE);
61 PROVIDE(_vdso_data = .);
62
63 /DISCARD/ : { 61 /DISCARD/ : {
64 *(.note.GNU-stack) 62 *(.note.GNU-stack)
65 *(.data .data.* .gnu.linkonce.d.* .sdata*) 63 *(.data .data.* .gnu.linkonce.d.* .sdata*)