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

Commit ebeb8c82 authored by Dominik Brodowski's avatar Dominik Brodowski Committed by Ingo Molnar
Browse files

syscalls/x86: Use 'struct pt_regs' based syscall calling for IA32_EMULATION and x32



Extend ARCH_HAS_SYSCALL_WRAPPER for i386 emulation and for x32 on 64-bit
x86.

For x32, all we need to do is to create an additional stub for each
compat syscall which decodes the parameters in x86-64 ordering, e.g.:

	asmlinkage long __compat_sys_x32_xyzzy(struct pt_regs *regs)
	{
		return c_SyS_xyzzy(regs->di, regs->si, regs->dx);
	}

For i386 emulation, we need to teach compat_sys_*() to take struct
pt_regs as its only argument, e.g.:

	asmlinkage long __compat_sys_ia32_xyzzy(struct pt_regs *regs)
	{
		return c_SyS_xyzzy(regs->bx, regs->cx, regs->dx);
	}

In addition, we need to create additional stubs for common syscalls
(that is, for syscalls which have the same parameters on 32-bit and
64-bit), e.g.:

	asmlinkage long __sys_ia32_xyzzy(struct pt_regs *regs)
	{
		return c_sys_xyzzy(regs->bx, regs->cx, regs->dx);
	}

This approach avoids leaking random user-provided register content down
the call chain.

This patch is based on an original proof-of-concept

 | From: Linus Torvalds <torvalds@linux-foundation.org>
 | Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>

and was split up and heavily modified by me, in particular to base it on
ARCH_HAS_SYSCALL_WRAPPER.

Signed-off-by: default avatarDominik Brodowski <linux@dominikbrodowski.net>
Acked-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20180405095307.3730-6-linux@dominikbrodowski.net


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 7303e30e
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -2957,5 +2957,5 @@ source "lib/Kconfig"


config SYSCALL_PTREGS
config SYSCALL_PTREGS
	def_bool y
	def_bool y
	depends on X86_64 && !COMPAT
	depends on X86_64
	select ARCH_HAS_SYSCALL_WRAPPER
	select ARCH_HAS_SYSCALL_WRAPPER
+4 −0
Original line number Original line Diff line number Diff line
@@ -325,6 +325,9 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)


	if (likely(nr < IA32_NR_syscalls)) {
	if (likely(nr < IA32_NR_syscalls)) {
		nr = array_index_nospec(nr, IA32_NR_syscalls);
		nr = array_index_nospec(nr, IA32_NR_syscalls);
#ifdef CONFIG_SYSCALL_PTREGS
		regs->ax = ia32_sys_call_table[nr](regs);
#else
		/*
		/*
		 * It's possible that a 32-bit syscall implementation
		 * It's possible that a 32-bit syscall implementation
		 * takes a 64-bit parameter but nonetheless assumes that
		 * takes a 64-bit parameter but nonetheless assumes that
@@ -335,6 +338,7 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs)
			(unsigned int)regs->bx, (unsigned int)regs->cx,
			(unsigned int)regs->bx, (unsigned int)regs->cx,
			(unsigned int)regs->dx, (unsigned int)regs->si,
			(unsigned int)regs->dx, (unsigned int)regs->si,
			(unsigned int)regs->di, (unsigned int)regs->bp);
			(unsigned int)regs->di, (unsigned int)regs->bp);
#endif /* CONFIG_SYSCALL_PTREGS */
	}
	}


	syscall_return_slowpath(regs);
	syscall_return_slowpath(regs);
+12 −3
Original line number Original line Diff line number Diff line
@@ -7,14 +7,23 @@
#include <asm/asm-offsets.h>
#include <asm/asm-offsets.h>
#include <asm/syscall.h>
#include <asm/syscall.h>


#ifdef CONFIG_SYSCALL_PTREGS
/* On X86_64, we use struct pt_regs * to pass parameters to syscalls */
#define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(const struct pt_regs *);

/* this is a lie, but it does not hurt as sys_ni_syscall just returns -EINVAL */
extern asmlinkage long sys_ni_syscall(const struct pt_regs *);

#else /* CONFIG_SYSCALL_PTREGS */
#define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
#define __SYSCALL_I386(nr, sym, qual) extern asmlinkage long sym(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
#endif /* CONFIG_SYSCALL_PTREGS */

#include <asm/syscalls_32.h>
#include <asm/syscalls_32.h>
#undef __SYSCALL_I386
#undef __SYSCALL_I386


#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,
#define __SYSCALL_I386(nr, sym, qual) [nr] = sym,


extern asmlinkage long sys_ni_syscall(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);

__visible const sys_call_ptr_t ia32_sys_call_table[__NR_syscall_compat_max+1] = {
__visible const sys_call_ptr_t ia32_sys_call_table[__NR_syscall_compat_max+1] = {
	/*
	/*
	 * Smells like a compiler bug -- it doesn't work
	 * Smells like a compiler bug -- it doesn't work
+341 −336

File changed.

Preview size limit exceeded, changes collapsed.

+38 −36
Original line number Original line Diff line number Diff line
@@ -342,41 +342,43 @@


#
#
# x32-specific system call numbers start at 512 to avoid cache impact
# x32-specific system call numbers start at 512 to avoid cache impact
# for native 64-bit operation.
# for native 64-bit operation. The __compat_sys_x32 stubs are created
# on-the-fly for compat_sys_*() compatibility system calls if X86_X32
# is defined.
#
#
512	x32	rt_sigaction		compat_sys_rt_sigaction
512	x32	rt_sigaction		__compat_sys_x32_rt_sigaction
513	x32	rt_sigreturn		sys32_x32_rt_sigreturn
513	x32	rt_sigreturn		sys32_x32_rt_sigreturn
514	x32	ioctl			compat_sys_ioctl
514	x32	ioctl			__compat_sys_x32_ioctl
515	x32	readv			compat_sys_readv
515	x32	readv			__compat_sys_x32_readv
516	x32	writev			compat_sys_writev
516	x32	writev			__compat_sys_x32_writev
517	x32	recvfrom		compat_sys_recvfrom
517	x32	recvfrom		__compat_sys_x32_recvfrom
518	x32	sendmsg			compat_sys_sendmsg
518	x32	sendmsg			__compat_sys_x32_sendmsg
519	x32	recvmsg			compat_sys_recvmsg
519	x32	recvmsg			__compat_sys_x32_recvmsg
520	x32	execve			compat_sys_execve/ptregs
520	x32	execve			__compat_sys_x32_execve/ptregs
521	x32	ptrace			compat_sys_ptrace
521	x32	ptrace			__compat_sys_x32_ptrace
522	x32	rt_sigpending		compat_sys_rt_sigpending
522	x32	rt_sigpending		__compat_sys_x32_rt_sigpending
523	x32	rt_sigtimedwait		compat_sys_rt_sigtimedwait
523	x32	rt_sigtimedwait		__compat_sys_x32_rt_sigtimedwait
524	x32	rt_sigqueueinfo		compat_sys_rt_sigqueueinfo
524	x32	rt_sigqueueinfo		__compat_sys_x32_rt_sigqueueinfo
525	x32	sigaltstack		compat_sys_sigaltstack
525	x32	sigaltstack		__compat_sys_x32_sigaltstack
526	x32	timer_create		compat_sys_timer_create
526	x32	timer_create		__compat_sys_x32_timer_create
527	x32	mq_notify		compat_sys_mq_notify
527	x32	mq_notify		__compat_sys_x32_mq_notify
528	x32	kexec_load		compat_sys_kexec_load
528	x32	kexec_load		__compat_sys_x32_kexec_load
529	x32	waitid			compat_sys_waitid
529	x32	waitid			__compat_sys_x32_waitid
530	x32	set_robust_list		compat_sys_set_robust_list
530	x32	set_robust_list		__compat_sys_x32_set_robust_list
531	x32	get_robust_list		compat_sys_get_robust_list
531	x32	get_robust_list		__compat_sys_x32_get_robust_list
532	x32	vmsplice		compat_sys_vmsplice
532	x32	vmsplice		__compat_sys_x32_vmsplice
533	x32	move_pages		compat_sys_move_pages
533	x32	move_pages		__compat_sys_x32_move_pages
534	x32	preadv			compat_sys_preadv64
534	x32	preadv			__compat_sys_x32_preadv64
535	x32	pwritev			compat_sys_pwritev64
535	x32	pwritev			__compat_sys_x32_pwritev64
536	x32	rt_tgsigqueueinfo	compat_sys_rt_tgsigqueueinfo
536	x32	rt_tgsigqueueinfo	__compat_sys_x32_rt_tgsigqueueinfo
537	x32	recvmmsg		compat_sys_recvmmsg
537	x32	recvmmsg		__compat_sys_x32_recvmmsg
538	x32	sendmmsg		compat_sys_sendmmsg
538	x32	sendmmsg		__compat_sys_x32_sendmmsg
539	x32	process_vm_readv	compat_sys_process_vm_readv
539	x32	process_vm_readv	__compat_sys_x32_process_vm_readv
540	x32	process_vm_writev	compat_sys_process_vm_writev
540	x32	process_vm_writev	__compat_sys_x32_process_vm_writev
541	x32	setsockopt		compat_sys_setsockopt
541	x32	setsockopt		__compat_sys_x32_setsockopt
542	x32	getsockopt		compat_sys_getsockopt
542	x32	getsockopt		__compat_sys_x32_getsockopt
543	x32	io_setup		compat_sys_io_setup
543	x32	io_setup		__compat_sys_x32_io_setup
544	x32	io_submit		compat_sys_io_submit
544	x32	io_submit		__compat_sys_x32_io_submit
545	x32	execveat		compat_sys_execveat/ptregs
545	x32	execveat		__compat_sys_x32_execveat/ptregs
546	x32	preadv2			compat_sys_preadv64v2
546	x32	preadv2			__compat_sys_x32_preadv64v2
547	x32	pwritev2		compat_sys_pwritev64v2
547	x32	pwritev2		__compat_sys_x32_pwritev64v2
Loading