Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b67e612c authored by Andy Lutomirski's avatar Andy Lutomirski Committed by H. Peter Anvin
Browse files

x86: Load the 32-bit vdso in place, just like the 64-bit vdsos



This replaces a decent amount of incomprehensible and buggy code
with much more straightforward code.  It also brings the 32-bit vdso
more in line with the 64-bit vdsos, so maybe someday they can share
even more code.

This wastes a small amount of kernel .data and .text space, but it
avoids a couple of allocations on startup, so it should be more or
less a wash memory-wise.

Signed-off-by: default avatarAndy Lutomirski <luto@amacapital.net>
Cc: Stefani Seibold <stefani@seibold.net>
Link: http://lkml.kernel.org/r/b8093933fad09ce181edb08a61dcd5d2592e9814.1395352498.git.luto@amacapital.net


Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent 4e40112c
Loading
Loading
Loading
Loading
+0 −8
Original line number Diff line number Diff line
@@ -25,14 +25,6 @@ extern const char VDSO32_PRELINK[];
extern void __user __kernel_sigreturn;
extern void __user __kernel_rt_sigreturn;

/*
 * These symbols are defined by vdso32.S to mark the bounds
 * of the ELF DSO images included therein.
 */
extern const char vdso32_int80_start, vdso32_int80_end;
extern const char vdso32_syscall_start, vdso32_syscall_end;
extern const char vdso32_sysenter_start, vdso32_sysenter_end;

void __init patch_vdso32(void *vdso, size_t len);

#endif /* _ASM_X86_VDSO_H */
+2 −20
Original line number Diff line number Diff line
#include <asm/page_types.h>
#include <linux/linkage.h>
#include "vdso_image.h"

__PAGE_ALIGNED_DATA

	.globl vdso_start, vdso_end
	.align PAGE_SIZE
vdso_start:
	.incbin "arch/x86/vdso/vdso.so"
vdso_end:
	.align PAGE_SIZE /* extra data here leaks to userspace. */

.previous

	.globl vdso_pages
	.bss
	.align 8
	.type vdso_pages, @object
vdso_pages:
	.zero (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE * 8
	.size vdso_pages, .-vdso_pages
DEFINE_VDSO_IMAGE(vdso, "arch/x86/vdso/vdso.so")
+29 −21
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <asm/fixmap.h>
#include <asm/hpet.h>
#include <asm/vvar.h>
#include "vdso_image.h"

#ifdef CONFIG_COMPAT_VDSO
#define VDSO_DEFAULT	0
@@ -41,6 +42,12 @@
#define arch_setup_additional_pages	syscall32_setup_pages
#endif

DECLARE_VDSO_IMAGE(vdso32_int80);
#ifdef CONFIG_COMPAT
DECLARE_VDSO_IMAGE(vdso32_syscall);
#endif
DECLARE_VDSO_IMAGE(vdso32_sysenter);

/*
 * Should the kernel map a VDSO page into processes and pass its
 * address down to glibc upon exec()?
@@ -71,7 +78,7 @@ EXPORT_SYMBOL_GPL(vdso_enabled);
#endif

static struct page **vdso32_pages;
static unsigned int vdso32_size;
static unsigned vdso32_size;

#ifdef CONFIG_X86_64

@@ -117,31 +124,32 @@ void enable_sep_cpu(void)

int __init sysenter_setup(void)
{
	void *vdso_pages;
	const void *vdso;
	size_t vdso_len;
	unsigned int i;
	char *vdso32_start, *vdso32_end;
	int npages, i;

#ifdef CONFIG_COMPAT
	if (vdso32_syscall()) {
		vdso = &vdso32_syscall_start;
		vdso_len = &vdso32_syscall_end - &vdso32_syscall_start;
	} else if (vdso32_sysenter()){
		vdso = &vdso32_sysenter_start;
		vdso_len = &vdso32_sysenter_end - &vdso32_sysenter_start;
		vdso32_start = vdso32_syscall_start;
		vdso32_end = vdso32_syscall_end;
		vdso32_pages = vdso32_syscall_pages;
	} else
#endif
	if (vdso32_sysenter()) {
		vdso32_start = vdso32_sysenter_start;
		vdso32_end = vdso32_sysenter_end;
		vdso32_pages = vdso32_sysenter_pages;
	} else {
		vdso = &vdso32_int80_start;
		vdso_len = &vdso32_int80_end - &vdso32_int80_start;
		vdso32_start = vdso32_int80_start;
		vdso32_end = vdso32_int80_end;
		vdso32_pages = vdso32_int80_pages;
	}

	vdso32_size = (vdso_len + PAGE_SIZE - 1) / PAGE_SIZE;
	vdso32_pages = kmalloc(sizeof(*vdso32_pages) * vdso32_size, GFP_ATOMIC);
	vdso_pages = kmalloc(VDSO_OFFSET(vdso32_size), GFP_ATOMIC);

	for(i = 0; i != vdso32_size; ++i)
		vdso32_pages[i] = virt_to_page(vdso_pages + VDSO_OFFSET(i));
	npages = ((vdso32_end - vdso32_start) + PAGE_SIZE - 1) / PAGE_SIZE;
	vdso32_size = npages << PAGE_SHIFT;
	for (i = 0; i < npages; i++)
		vdso32_pages[i] = virt_to_page(vdso32_start + i*PAGE_SIZE);

	memcpy(vdso_pages, vdso, vdso_len);
	patch_vdso32(vdso_pages, vdso_len);
	patch_vdso32(vdso32_start, vdso32_size);

	return 0;
}
@@ -177,7 +185,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
	 */
	ret = install_special_mapping(mm,
			addr,
			VDSO_OFFSET(vdso32_size),
			vdso32_size,
			VM_READ|VM_EXEC|
			VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
			vdso32_pages);
+4 −17
Original line number Diff line number Diff line
#include <linux/init.h>
#include "vdso_image.h"

__INITDATA
DEFINE_VDSO_IMAGE(vdso32_int80, "arch/x86/vdso/vdso32-int80.so")

	.globl vdso32_int80_start, vdso32_int80_end
vdso32_int80_start:
	.incbin "arch/x86/vdso/vdso32-int80.so"
vdso32_int80_end:

	.globl vdso32_syscall_start, vdso32_syscall_end
vdso32_syscall_start:
#ifdef CONFIG_COMPAT
	.incbin "arch/x86/vdso/vdso32-syscall.so"
DEFINE_VDSO_IMAGE(vdso32_syscall, "arch/x86/vdso/vdso32-syscall.so")
#endif
vdso32_syscall_end:

	.globl vdso32_sysenter_start, vdso32_sysenter_end
vdso32_sysenter_start:
	.incbin "arch/x86/vdso/vdso32-sysenter.so"
vdso32_sysenter_end:

__FINIT
DEFINE_VDSO_IMAGE(vdso32_sysenter, "arch/x86/vdso/vdso32-sysenter.so")
+30 −0
Original line number Diff line number Diff line
#ifndef _VDSO_IMAGE_H
#define _VDSO_IMAGE_H

#include <asm/page_types.h>
#include <linux/linkage.h>

#define DEFINE_VDSO_IMAGE(symname, filename)				\
__PAGE_ALIGNED_DATA ;							\
	.globl symname##_start, symname##_end ;				\
	.align PAGE_SIZE ;						\
	symname##_start: ;						\
	.incbin filename ;						\
	symname##_end: ;						\
	.align PAGE_SIZE /* extra data here leaks to userspace. */ ;	\
									\
.previous ;								\
									\
	.globl symname##_pages ;					\
	.bss ;								\
	.align 8 ;							\
	.type symname##_pages, @object ;				\
	symname##_pages: ;						\
	.zero (symname##_end - symname##_start + PAGE_SIZE - 1) / PAGE_SIZE * (BITS_PER_LONG / 8) ; \
	.size symname##_pages, .-symname##_pages

#define DECLARE_VDSO_IMAGE(symname)				\
	extern char symname##_start[], symname##_end[];		\
	extern struct page *symname##_pages[]

#endif /* _VDSO_IMAGE_H */
Loading