Skip to content

Commit 8e4ef63

Browse files
committed
Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 vdso updates from Ingo Molnar: "The main changes in this cycle centered around adding support for 32-bit compatible C/R of the vDSO on 64-bit kernels, by Dmitry Safonov" * 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/vdso: Use CONFIG_X86_X32_ABI to enable vdso prctl x86/vdso: Only define map_vdso_randomized() if CONFIG_X86_64 x86/vdso: Only define prctl_map_vdso() if CONFIG_CHECKPOINT_RESTORE x86/signal: Add SA_{X32,IA32}_ABI sa_flags x86/ptrace: Down with test_thread_flag(TIF_IA32) x86/coredump: Use pr_reg size, rather that TIF_IA32 flag x86/arch_prctl/vdso: Add ARCH_MAP_VDSO_* x86/vdso: Replace calculate_addr in map_vdso() with addr x86/vdso: Unmap vdso blob on vvar mapping failure
2 parents 6aebe7f + 6e68b08 commit 8e4ef63

15 files changed

Lines changed: 220 additions & 106 deletions

File tree

arch/x86/entry/vdso/vma.c

Lines changed: 102 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -37,54 +37,6 @@ void __init init_vdso_image(const struct vdso_image *image)
3737

3838
struct linux_binprm;
3939

40-
/*
41-
* Put the vdso above the (randomized) stack with another randomized
42-
* offset. This way there is no hole in the middle of address space.
43-
* To save memory make sure it is still in the same PTE as the stack
44-
* top. This doesn't give that many random bits.
45-
*
46-
* Note that this algorithm is imperfect: the distribution of the vdso
47-
* start address within a PMD is biased toward the end.
48-
*
49-
* Only used for the 64-bit and x32 vdsos.
50-
*/
51-
static unsigned long vdso_addr(unsigned long start, unsigned len)
52-
{
53-
#ifdef CONFIG_X86_32
54-
return 0;
55-
#else
56-
unsigned long addr, end;
57-
unsigned offset;
58-
59-
/*
60-
* Round up the start address. It can start out unaligned as a result
61-
* of stack start randomization.
62-
*/
63-
start = PAGE_ALIGN(start);
64-
65-
/* Round the lowest possible end address up to a PMD boundary. */
66-
end = (start + len + PMD_SIZE - 1) & PMD_MASK;
67-
if (end >= TASK_SIZE_MAX)
68-
end = TASK_SIZE_MAX;
69-
end -= len;
70-
71-
if (end > start) {
72-
offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
73-
addr = start + (offset << PAGE_SHIFT);
74-
} else {
75-
addr = start;
76-
}
77-
78-
/*
79-
* Forcibly align the final address in case we have a hardware
80-
* issue that requires alignment for performance reasons.
81-
*/
82-
addr = align_vdso_addr(addr);
83-
84-
return addr;
85-
#endif
86-
}
87-
8840
static int vdso_fault(const struct vm_special_mapping *sm,
8941
struct vm_area_struct *vma, struct vm_fault *vmf)
9042
{
@@ -176,30 +128,28 @@ static int vvar_fault(const struct vm_special_mapping *sm,
176128
return VM_FAULT_SIGBUS;
177129
}
178130

179-
static int map_vdso(const struct vdso_image *image, bool calculate_addr)
131+
static const struct vm_special_mapping vdso_mapping = {
132+
.name = "[vdso]",
133+
.fault = vdso_fault,
134+
.mremap = vdso_mremap,
135+
};
136+
static const struct vm_special_mapping vvar_mapping = {
137+
.name = "[vvar]",
138+
.fault = vvar_fault,
139+
};
140+
141+
/*
142+
* Add vdso and vvar mappings to current process.
143+
* @image - blob to map
144+
* @addr - request a specific address (zero to map at free addr)
145+
*/
146+
static int map_vdso(const struct vdso_image *image, unsigned long addr)
180147
{
181148
struct mm_struct *mm = current->mm;
182149
struct vm_area_struct *vma;
183-
unsigned long addr, text_start;
150+
unsigned long text_start;
184151
int ret = 0;
185152

186-
static const struct vm_special_mapping vdso_mapping = {
187-
.name = "[vdso]",
188-
.fault = vdso_fault,
189-
.mremap = vdso_mremap,
190-
};
191-
static const struct vm_special_mapping vvar_mapping = {
192-
.name = "[vvar]",
193-
.fault = vvar_fault,
194-
};
195-
196-
if (calculate_addr) {
197-
addr = vdso_addr(current->mm->start_stack,
198-
image->size - image->sym_vvar_start);
199-
} else {
200-
addr = 0;
201-
}
202-
203153
if (down_write_killable(&mm->mmap_sem))
204154
return -EINTR;
205155

@@ -238,24 +188,104 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
238188

239189
if (IS_ERR(vma)) {
240190
ret = PTR_ERR(vma);
241-
goto up_fail;
191+
do_munmap(mm, text_start, image->size);
242192
}
243193

244194
up_fail:
245-
if (ret)
195+
if (ret) {
246196
current->mm->context.vdso = NULL;
197+
current->mm->context.vdso_image = NULL;
198+
}
247199

248200
up_write(&mm->mmap_sem);
249201
return ret;
250202
}
251203

204+
#ifdef CONFIG_X86_64
205+
/*
206+
* Put the vdso above the (randomized) stack with another randomized
207+
* offset. This way there is no hole in the middle of address space.
208+
* To save memory make sure it is still in the same PTE as the stack
209+
* top. This doesn't give that many random bits.
210+
*
211+
* Note that this algorithm is imperfect: the distribution of the vdso
212+
* start address within a PMD is biased toward the end.
213+
*
214+
* Only used for the 64-bit and x32 vdsos.
215+
*/
216+
static unsigned long vdso_addr(unsigned long start, unsigned len)
217+
{
218+
unsigned long addr, end;
219+
unsigned offset;
220+
221+
/*
222+
* Round up the start address. It can start out unaligned as a result
223+
* of stack start randomization.
224+
*/
225+
start = PAGE_ALIGN(start);
226+
227+
/* Round the lowest possible end address up to a PMD boundary. */
228+
end = (start + len + PMD_SIZE - 1) & PMD_MASK;
229+
if (end >= TASK_SIZE_MAX)
230+
end = TASK_SIZE_MAX;
231+
end -= len;
232+
233+
if (end > start) {
234+
offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
235+
addr = start + (offset << PAGE_SHIFT);
236+
} else {
237+
addr = start;
238+
}
239+
240+
/*
241+
* Forcibly align the final address in case we have a hardware
242+
* issue that requires alignment for performance reasons.
243+
*/
244+
addr = align_vdso_addr(addr);
245+
246+
return addr;
247+
}
248+
249+
static int map_vdso_randomized(const struct vdso_image *image)
250+
{
251+
unsigned long addr = vdso_addr(current->mm->start_stack, image->size-image->sym_vvar_start);
252+
253+
return map_vdso(image, addr);
254+
}
255+
#endif
256+
257+
int map_vdso_once(const struct vdso_image *image, unsigned long addr)
258+
{
259+
struct mm_struct *mm = current->mm;
260+
struct vm_area_struct *vma;
261+
262+
down_write(&mm->mmap_sem);
263+
/*
264+
* Check if we have already mapped vdso blob - fail to prevent
265+
* abusing from userspace install_speciall_mapping, which may
266+
* not do accounting and rlimit right.
267+
* We could search vma near context.vdso, but it's a slowpath,
268+
* so let's explicitely check all VMAs to be completely sure.
269+
*/
270+
for (vma = mm->mmap; vma; vma = vma->vm_next) {
271+
if (vma_is_special_mapping(vma, &vdso_mapping) ||
272+
vma_is_special_mapping(vma, &vvar_mapping)) {
273+
up_write(&mm->mmap_sem);
274+
return -EEXIST;
275+
}
276+
}
277+
up_write(&mm->mmap_sem);
278+
279+
return map_vdso(image, addr);
280+
}
281+
252282
#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
253283
static int load_vdso32(void)
254284
{
255285
if (vdso32_enabled != 1) /* Other values all mean "disabled" */
256286
return 0;
257287

258-
return map_vdso(&vdso_image_32, false);
288+
return map_vdso(&vdso_image_32, 0);
259289
}
260290
#endif
261291

@@ -265,7 +295,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
265295
if (!vdso64_enabled)
266296
return 0;
267297

268-
return map_vdso(&vdso_image_64, true);
298+
return map_vdso_randomized(&vdso_image_64);
269299
}
270300

271301
#ifdef CONFIG_COMPAT
@@ -276,8 +306,7 @@ int compat_arch_setup_additional_pages(struct linux_binprm *bprm,
276306
if (test_thread_flag(TIF_X32)) {
277307
if (!vdso64_enabled)
278308
return 0;
279-
280-
return map_vdso(&vdso_image_x32, true);
309+
return map_vdso_randomized(&vdso_image_x32);
281310
}
282311
#endif
283312
#ifdef CONFIG_IA32_EMULATION

arch/x86/ia32/ia32_signal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ int ia32_setup_rt_frame(int sig, struct ksignal *ksig,
378378
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
379379
} put_user_catch(err);
380380

381-
err |= copy_siginfo_to_user32(&frame->info, &ksig->info);
381+
err |= __copy_siginfo_to_user32(&frame->info, &ksig->info, false);
382382
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
383383
regs, set->sig[0]);
384384
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

arch/x86/include/asm/compat.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,10 @@ struct compat_shmid64_ds {
275275
#ifdef CONFIG_X86_X32_ABI
276276
typedef struct user_regs_struct compat_elf_gregset_t;
277277

278-
#define PR_REG_SIZE(S) (test_thread_flag(TIF_IA32) ? 68 : 216)
279-
#define PRSTATUS_SIZE(S) (test_thread_flag(TIF_IA32) ? 144 : 296)
280-
#define SET_PR_FPVALID(S,V) \
281-
do { *(int *) (((void *) &((S)->pr_reg)) + PR_REG_SIZE(0)) = (V); } \
278+
/* Full regset -- prstatus on x32, otherwise on ia32 */
279+
#define PRSTATUS_SIZE(S, R) (R != sizeof(S.pr_reg) ? 144 : 296)
280+
#define SET_PR_FPVALID(S, V, R) \
281+
do { *(int *) (((void *) &((S)->pr_reg)) + R) = (V); } \
282282
while (0)
283283

284284
#define COMPAT_USE_64BIT_TIME \

arch/x86/include/asm/fpu/signal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ int ia32_setup_frame(int sig, struct ksignal *ksig,
1919
# define ia32_setup_rt_frame __setup_rt_frame
2020
#endif
2121

22+
#ifdef CONFIG_COMPAT
23+
int __copy_siginfo_to_user32(compat_siginfo_t __user *to,
24+
const siginfo_t *from, bool x32_ABI);
25+
#endif
26+
27+
2228
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
2329
struct task_struct *tsk);
2430
extern void convert_to_fxsr(struct task_struct *tsk,

arch/x86/include/asm/signal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ typedef struct {
2323
unsigned long sig[_NSIG_WORDS];
2424
} sigset_t;
2525

26+
/* non-uapi in-kernel SA_FLAGS for those indicates ABI for a signal frame */
27+
#define SA_IA32_ABI 0x02000000u
28+
#define SA_X32_ABI 0x01000000u
29+
2630
#ifndef CONFIG_COMPAT
2731
typedef sigset_t compat_sigset_t;
2832
#endif

arch/x86/include/asm/vdso.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ extern const struct vdso_image vdso_image_32;
4141

4242
extern void __init init_vdso_image(const struct vdso_image *image);
4343

44+
extern int map_vdso_once(const struct vdso_image *image, unsigned long addr);
45+
4446
#endif /* __ASSEMBLER__ */
4547

4648
#endif /* _ASM_X86_VDSO_H */

arch/x86/include/uapi/asm/prctl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,10 @@
66
#define ARCH_GET_FS 0x1003
77
#define ARCH_GET_GS 0x1004
88

9+
#ifdef CONFIG_CHECKPOINT_RESTORE
10+
# define ARCH_MAP_VDSO_X32 0x2001
11+
# define ARCH_MAP_VDSO_32 0x2002
12+
# define ARCH_MAP_VDSO_64 0x2003
13+
#endif
14+
915
#endif /* _ASM_X86_PRCTL_H */

arch/x86/kernel/process_64.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include <asm/debugreg.h>
5050
#include <asm/switch_to.h>
5151
#include <asm/xen/hypervisor.h>
52+
#include <asm/vdso.h>
5253

5354
__visible DEFINE_PER_CPU(unsigned long, rsp_scratch);
5455

@@ -523,6 +524,19 @@ void set_personality_ia32(bool x32)
523524
}
524525
EXPORT_SYMBOL_GPL(set_personality_ia32);
525526

527+
#ifdef CONFIG_CHECKPOINT_RESTORE
528+
static long prctl_map_vdso(const struct vdso_image *image, unsigned long addr)
529+
{
530+
int ret;
531+
532+
ret = map_vdso_once(image, addr);
533+
if (ret)
534+
return ret;
535+
536+
return (long)image->size;
537+
}
538+
#endif
539+
526540
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
527541
{
528542
int ret = 0;
@@ -576,6 +590,19 @@ long do_arch_prctl(struct task_struct *task, int code, unsigned long addr)
576590
break;
577591
}
578592

593+
#ifdef CONFIG_CHECKPOINT_RESTORE
594+
# ifdef CONFIG_X86_X32_ABI
595+
case ARCH_MAP_VDSO_X32:
596+
return prctl_map_vdso(&vdso_image_x32, addr);
597+
# endif
598+
# if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
599+
case ARCH_MAP_VDSO_32:
600+
return prctl_map_vdso(&vdso_image_32, addr);
601+
# endif
602+
case ARCH_MAP_VDSO_64:
603+
return prctl_map_vdso(&vdso_image_64, addr);
604+
#endif
605+
579606
default:
580607
ret = -EINVAL;
581608
break;

arch/x86/kernel/ptrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,7 @@ void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask)
13581358
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
13591359
{
13601360
#ifdef CONFIG_IA32_EMULATION
1361-
if (test_tsk_thread_flag(task, TIF_IA32))
1361+
if (!user_64bit_mode(task_pt_regs(task)))
13621362
#endif
13631363
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
13641364
return &user_x86_32_view;

0 commit comments

Comments
 (0)