Commit 253f29a4 authored by Brian Gerst's avatar Brian Gerst Committed by Ingo Molnar

x86: pass in pt_regs pointer for syscalls that need it

Some syscalls need to access the pt_regs structure, either to copy
user register state or to modifiy it.  This patch adds stubs to load
the address of the pt_regs struct into the %eax register, and changes
the syscalls to regparm(1) to receive the pt_regs pointer as the
first argument.
Signed-off-by: default avatarBrian Gerst <brgerst@gmail.com>
Acked-by: default avatarTejun Heo <tj@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent aa78bcfa
...@@ -17,6 +17,13 @@ ...@@ -17,6 +17,13 @@
*/ */
#define asmregparm __attribute__((regparm(3))) #define asmregparm __attribute__((regparm(3)))
/*
* For syscalls that need a pointer to the pt_regs struct (ie. fork).
* The regs pointer is passed in %eax as the first argument. The
* remaining function arguments remain on the stack.
*/
#define ptregscall __attribute__((regparm(1)))
/* /*
* Make sure the compiler doesn't do anything stupid with the * Make sure the compiler doesn't do anything stupid with the
* arguments on the stack - they are owned by the *caller*, not * arguments on the stack - they are owned by the *caller*, not
......
...@@ -29,21 +29,26 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *); ...@@ -29,21 +29,26 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *);
/* X86_32 only */ /* X86_32 only */
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
/* kernel/process_32.c */ /* kernel/process_32.c */
asmlinkage int sys_fork(struct pt_regs); ptregscall int sys_fork(struct pt_regs *);
asmlinkage int sys_clone(struct pt_regs); ptregscall int sys_clone(struct pt_regs *, unsigned long,
asmlinkage int sys_vfork(struct pt_regs); unsigned long, int __user *,
asmlinkage int sys_execve(struct pt_regs); unsigned long, int __user *);
ptregscall int sys_vfork(struct pt_regs *);
ptregscall int sys_execve(struct pt_regs *, char __user *,
char __user * __user *,
char __user * __user *);
/* kernel/signal_32.c */ /* kernel/signal_32.c */
asmlinkage int sys_sigsuspend(int, int, old_sigset_t); asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
struct old_sigaction __user *); struct old_sigaction __user *);
asmlinkage int sys_sigaltstack(unsigned long); ptregscall int sys_sigaltstack(struct pt_regs *, const stack_t __user *,
asmlinkage unsigned long sys_sigreturn(unsigned long); stack_t __user *);
asmlinkage int sys_rt_sigreturn(unsigned long); ptregscall unsigned long sys_sigreturn(struct pt_regs *);
ptregscall int sys_rt_sigreturn(struct pt_regs *);
/* kernel/ioport.c */ /* kernel/ioport.c */
asmlinkage long sys_iopl(unsigned long); ptregscall long sys_iopl(struct pt_regs *, unsigned int);
/* kernel/sys_i386_32.c */ /* kernel/sys_i386_32.c */
asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
...@@ -59,8 +64,8 @@ struct oldold_utsname; ...@@ -59,8 +64,8 @@ struct oldold_utsname;
asmlinkage int sys_olduname(struct oldold_utsname __user *); asmlinkage int sys_olduname(struct oldold_utsname __user *);
/* kernel/vm86_32.c */ /* kernel/vm86_32.c */
asmlinkage int sys_vm86old(struct pt_regs); ptregscall int sys_vm86old(struct pt_regs *, struct vm86_struct __user *);
asmlinkage int sys_vm86(struct pt_regs); ptregscall int sys_vm86(struct pt_regs *, unsigned long, unsigned long);
#else /* CONFIG_X86_32 */ #else /* CONFIG_X86_32 */
......
...@@ -697,6 +697,26 @@ syscall_badsys: ...@@ -697,6 +697,26 @@ syscall_badsys:
END(syscall_badsys) END(syscall_badsys)
CFI_ENDPROC CFI_ENDPROC
/*
* System calls that need a pt_regs pointer.
*/
#define PTREGSCALL(name) \
ALIGN; \
ptregs_##name: \
leal 4(%esp),%eax; \
jmp sys_##name;
PTREGSCALL(iopl)
PTREGSCALL(fork)
PTREGSCALL(clone)
PTREGSCALL(vfork)
PTREGSCALL(execve)
PTREGSCALL(sigaltstack)
PTREGSCALL(sigreturn)
PTREGSCALL(rt_sigreturn)
PTREGSCALL(vm86)
PTREGSCALL(vm86old)
.macro FIXUP_ESPFIX_STACK .macro FIXUP_ESPFIX_STACK
/* since we are on a wrong stack, we cant make it a C code :( */ /* since we are on a wrong stack, we cant make it a C code :( */
PER_CPU(gdt_page, %ebx) PER_CPU(gdt_page, %ebx)
......
...@@ -131,10 +131,8 @@ static int do_iopl(unsigned int level, struct pt_regs *regs) ...@@ -131,10 +131,8 @@ static int do_iopl(unsigned int level, struct pt_regs *regs)
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
asmlinkage long sys_iopl(unsigned long regsp) ptregscall long sys_iopl(struct pt_regs *regs, unsigned int level)
{ {
struct pt_regs *regs = (struct pt_regs *)&regsp;
unsigned int level = regs->bx;
struct thread_struct *t = &current->thread; struct thread_struct *t = &current->thread;
int rc; int rc;
......
...@@ -603,24 +603,18 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) ...@@ -603,24 +603,18 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
return prev_p; return prev_p;
} }
asmlinkage int sys_fork(struct pt_regs regs) ptregscall int sys_fork(struct pt_regs *regs)
{ {
return do_fork(SIGCHLD, regs.sp, &regs, 0, NULL, NULL); return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
} }
asmlinkage int sys_clone(struct pt_regs regs) ptregscall int sys_clone(struct pt_regs *regs, unsigned long clone_flags,
unsigned long newsp, int __user *parent_tidptr,
unsigned long unused, int __user *child_tidptr)
{ {
unsigned long clone_flags;
unsigned long newsp;
int __user *parent_tidptr, *child_tidptr;
clone_flags = regs.bx;
newsp = regs.cx;
parent_tidptr = (int __user *)regs.dx;
child_tidptr = (int __user *)regs.di;
if (!newsp) if (!newsp)
newsp = regs.sp; newsp = regs->sp;
return do_fork(clone_flags, newsp, &regs, 0, parent_tidptr, child_tidptr); return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
} }
/* /*
...@@ -633,27 +627,26 @@ asmlinkage int sys_clone(struct pt_regs regs) ...@@ -633,27 +627,26 @@ asmlinkage int sys_clone(struct pt_regs regs)
* do not have enough call-clobbered registers to hold all * do not have enough call-clobbered registers to hold all
* the information you need. * the information you need.
*/ */
asmlinkage int sys_vfork(struct pt_regs regs) ptregscall int sys_vfork(struct pt_regs *regs)
{ {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, &regs, 0, NULL, NULL); return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL);
} }
/* /*
* sys_execve() executes a new program. * sys_execve() executes a new program.
*/ */
asmlinkage int sys_execve(struct pt_regs regs) ptregscall int sys_execve(struct pt_regs *regs, char __user *u_filename,
char __user * __user *argv,
char __user * __user *envp)
{ {
int error; int error;
char *filename; char *filename;
filename = getname((char __user *) regs.bx); filename = getname(u_filename);
error = PTR_ERR(filename); error = PTR_ERR(filename);
if (IS_ERR(filename)) if (IS_ERR(filename))
goto out; goto out;
error = do_execve(filename, error = do_execve(filename, argv, envp, regs);
(char __user * __user *) regs.cx,
(char __user * __user *) regs.dx,
&regs);
if (error == 0) { if (error == 0) {
/* Make sure we don't return using sysenter.. */ /* Make sure we don't return using sysenter.. */
set_thread_flag(TIF_IRET); set_thread_flag(TIF_IRET);
......
...@@ -549,39 +549,28 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, ...@@ -549,39 +549,28 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
asmlinkage int sys_sigaltstack(unsigned long bx) ptregscall int
{ sys_sigaltstack(struct pt_regs *regs, const stack_t __user *uss,
/* stack_t __user *uoss)
* This is needed to make gcc realize it doesn't own the
* "struct pt_regs"
*/
struct pt_regs *regs = (struct pt_regs *)&bx;
const stack_t __user *uss = (const stack_t __user *)bx;
stack_t __user *uoss = (stack_t __user *)regs->cx;
return do_sigaltstack(uss, uoss, regs->sp);
}
#else /* !CONFIG_X86_32 */ #else /* !CONFIG_X86_32 */
asmlinkage long asmlinkage long
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct pt_regs *regs) struct pt_regs *regs)
#endif /* CONFIG_X86_32 */
{ {
return do_sigaltstack(uss, uoss, regs->sp); return do_sigaltstack(uss, uoss, regs->sp);
} }
#endif /* CONFIG_X86_32 */
/* /*
* Do a signal return; undo the signal stack. * Do a signal return; undo the signal stack.
*/ */
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
asmlinkage unsigned long sys_sigreturn(unsigned long __unused) ptregscall unsigned long sys_sigreturn(struct pt_regs *regs)
{ {
struct sigframe __user *frame; struct sigframe __user *frame;
struct pt_regs *regs;
unsigned long ax; unsigned long ax;
sigset_t set; sigset_t set;
regs = (struct pt_regs *) &__unused;
frame = (struct sigframe __user *)(regs->sp - 8); frame = (struct sigframe __user *)(regs->sp - 8);
if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
...@@ -640,23 +629,13 @@ badframe: ...@@ -640,23 +629,13 @@ badframe:
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
/* ptregscall int sys_rt_sigreturn(struct pt_regs *regs)
* Note: do not pass in pt_regs directly as with tail-call optimization
* GCC will incorrectly stomp on the caller's frame and corrupt user-space
* register state:
*/
asmlinkage int sys_rt_sigreturn(unsigned long __unused)
{
struct pt_regs *regs = (struct pt_regs *)&__unused;
return do_rt_sigreturn(regs);
}
#else /* !CONFIG_X86_32 */ #else /* !CONFIG_X86_32 */
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
#endif /* CONFIG_X86_32 */
{ {
return do_rt_sigreturn(regs); return do_rt_sigreturn(regs);
} }
#endif /* CONFIG_X86_32 */
/* /*
* OK, we're invoking a handler: * OK, we're invoking a handler:
......
ENTRY(sys_call_table) ENTRY(sys_call_table)
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
.long sys_exit .long sys_exit
.long sys_fork .long ptregs_fork
.long sys_read .long sys_read
.long sys_write .long sys_write
.long sys_open /* 5 */ .long sys_open /* 5 */
...@@ -10,7 +10,7 @@ ENTRY(sys_call_table) ...@@ -10,7 +10,7 @@ ENTRY(sys_call_table)
.long sys_creat .long sys_creat
.long sys_link .long sys_link
.long sys_unlink /* 10 */ .long sys_unlink /* 10 */
.long sys_execve .long ptregs_execve
.long sys_chdir .long sys_chdir
.long sys_time .long sys_time
.long sys_mknod .long sys_mknod
...@@ -109,17 +109,17 @@ ENTRY(sys_call_table) ...@@ -109,17 +109,17 @@ ENTRY(sys_call_table)
.long sys_newlstat .long sys_newlstat
.long sys_newfstat .long sys_newfstat
.long sys_uname .long sys_uname
.long sys_iopl /* 110 */ .long ptregs_iopl /* 110 */
.long sys_vhangup .long sys_vhangup
.long sys_ni_syscall /* old "idle" system call */ .long sys_ni_syscall /* old "idle" system call */
.long sys_vm86old .long ptregs_vm86old
.long sys_wait4 .long sys_wait4
.long sys_swapoff /* 115 */ .long sys_swapoff /* 115 */
.long sys_sysinfo .long sys_sysinfo
.long sys_ipc .long sys_ipc
.long sys_fsync .long sys_fsync
.long sys_sigreturn .long ptregs_sigreturn
.long sys_clone /* 120 */ .long ptregs_clone /* 120 */
.long sys_setdomainname .long sys_setdomainname
.long sys_newuname .long sys_newuname
.long sys_modify_ldt .long sys_modify_ldt
...@@ -165,14 +165,14 @@ ENTRY(sys_call_table) ...@@ -165,14 +165,14 @@ ENTRY(sys_call_table)
.long sys_mremap .long sys_mremap
.long sys_setresuid16 .long sys_setresuid16
.long sys_getresuid16 /* 165 */ .long sys_getresuid16 /* 165 */
.long sys_vm86 .long ptregs_vm86
.long sys_ni_syscall /* Old sys_query_module */ .long sys_ni_syscall /* Old sys_query_module */
.long sys_poll .long sys_poll
.long sys_nfsservctl .long sys_nfsservctl
.long sys_setresgid16 /* 170 */ .long sys_setresgid16 /* 170 */
.long sys_getresgid16 .long sys_getresgid16
.long sys_prctl .long sys_prctl
.long sys_rt_sigreturn .long ptregs_rt_sigreturn
.long sys_rt_sigaction .long sys_rt_sigaction
.long sys_rt_sigprocmask /* 175 */ .long sys_rt_sigprocmask /* 175 */
.long sys_rt_sigpending .long sys_rt_sigpending
...@@ -185,11 +185,11 @@ ENTRY(sys_call_table) ...@@ -185,11 +185,11 @@ ENTRY(sys_call_table)
.long sys_getcwd .long sys_getcwd
.long sys_capget .long sys_capget
.long sys_capset /* 185 */ .long sys_capset /* 185 */
.long sys_sigaltstack .long ptregs_sigaltstack
.long sys_sendfile .long sys_sendfile
.long sys_ni_syscall /* reserved for streams1 */ .long sys_ni_syscall /* reserved for streams1 */
.long sys_ni_syscall /* reserved for streams2 */ .long sys_ni_syscall /* reserved for streams2 */
.long sys_vfork /* 190 */ .long ptregs_vfork /* 190 */
.long sys_getrlimit .long sys_getrlimit
.long sys_mmap2 .long sys_mmap2
.long sys_truncate64 .long sys_truncate64
......
...@@ -197,9 +197,8 @@ out: ...@@ -197,9 +197,8 @@ out:
static int do_vm86_irq_handling(int subfunction, int irqnumber); static int do_vm86_irq_handling(int subfunction, int irqnumber);
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk); static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
asmlinkage int sys_vm86old(struct pt_regs regs) ptregscall int sys_vm86old(struct pt_regs *regs, struct vm86_struct __user *v86)
{ {
struct vm86_struct __user *v86 = (struct vm86_struct __user *)regs.bx;
struct kernel_vm86_struct info; /* declare this _on top_, struct kernel_vm86_struct info; /* declare this _on top_,
* this avoids wasting of stack space. * this avoids wasting of stack space.
* This remains on the stack until we * This remains on the stack until we
...@@ -218,7 +217,7 @@ asmlinkage int sys_vm86old(struct pt_regs regs) ...@@ -218,7 +217,7 @@ asmlinkage int sys_vm86old(struct pt_regs regs)
if (tmp) if (tmp)
goto out; goto out;
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus); memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
info.regs32 = &regs; info.regs32 = regs;
tsk->thread.vm86_info = v86; tsk->thread.vm86_info = v86;
do_sys_vm86(&info, tsk); do_sys_vm86(&info, tsk);
ret = 0; /* we never return here */ ret = 0; /* we never return here */
...@@ -227,7 +226,7 @@ out: ...@@ -227,7 +226,7 @@ out:
} }
asmlinkage int sys_vm86(struct pt_regs regs) ptregscall int sys_vm86(struct pt_regs *regs, unsigned long cmd, unsigned long arg)
{ {
struct kernel_vm86_struct info; /* declare this _on top_, struct kernel_vm86_struct info; /* declare this _on top_,
* this avoids wasting of stack space. * this avoids wasting of stack space.
...@@ -239,12 +238,12 @@ asmlinkage int sys_vm86(struct pt_regs regs) ...@@ -239,12 +238,12 @@ asmlinkage int sys_vm86(struct pt_regs regs)
struct vm86plus_struct __user *v86; struct vm86plus_struct __user *v86;
tsk = current; tsk = current;
switch (regs.bx) { switch (cmd) {
case VM86_REQUEST_IRQ: case VM86_REQUEST_IRQ:
case VM86_FREE_IRQ: case VM86_FREE_IRQ:
case VM86_GET_IRQ_BITS: case VM86_GET_IRQ_BITS:
case VM86_GET_AND_RESET_IRQ: case VM86_GET_AND_RESET_IRQ:
ret = do_vm86_irq_handling(regs.bx, (int)regs.cx); ret = do_vm86_irq_handling(cmd, (int)arg);
goto out; goto out;
case VM86_PLUS_INSTALL_CHECK: case VM86_PLUS_INSTALL_CHECK:
/* /*
...@@ -261,14 +260,14 @@ asmlinkage int sys_vm86(struct pt_regs regs) ...@@ -261,14 +260,14 @@ asmlinkage int sys_vm86(struct pt_regs regs)
ret = -EPERM; ret = -EPERM;
if (tsk->thread.saved_sp0) if (tsk->thread.saved_sp0)
goto out; goto out;
v86 = (struct vm86plus_struct __user *)regs.cx; v86 = (struct vm86plus_struct __user *)arg;
tmp = copy_vm86_regs_from_user(&info.regs, &v86->regs, tmp = copy_vm86_regs_from_user(&info.regs, &v86->regs,
offsetof(struct kernel_vm86_struct, regs32) - offsetof(struct kernel_vm86_struct, regs32) -
sizeof(info.regs)); sizeof(info.regs));
ret = -EFAULT; ret = -EFAULT;
if (tmp) if (tmp)
goto out; goto out;
info.regs32 = &regs; info.regs32 = regs;
info.vm86plus.is_vm86pus = 1; info.vm86plus.is_vm86pus = 1;
tsk->thread.vm86_info = (struct vm86_struct __user *)v86; tsk->thread.vm86_info = (struct vm86_struct __user *)v86;
do_sys_vm86(&info, tsk); do_sys_vm86(&info, tsk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment