diff options
Diffstat (limited to 'arch/tile/kernel/compat_signal.c')
| -rw-r--r-- | arch/tile/kernel/compat_signal.c | 218 | 
1 files changed, 18 insertions, 200 deletions
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index fb64b99959d..19c04b5ce40 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c @@ -15,7 +15,6 @@  #include <linux/sched.h>  #include <linux/mm.h>  #include <linux/smp.h> -#include <linux/smp_lock.h>  #include <linux/kernel.h>  #include <linux/signal.h>  #include <linux/errno.h> @@ -33,21 +32,9 @@  #include <asm/ucontext.h>  #include <asm/sigframe.h>  #include <asm/syscalls.h> +#include <asm/vdso.h>  #include <arch/interrupts.h> -struct compat_sigaction { -	compat_uptr_t sa_handler; -	compat_ulong_t sa_flags; -	compat_uptr_t sa_restorer; -	sigset_t sa_mask __packed; -}; - -struct compat_sigaltstack { -	compat_uptr_t ss_sp; -	int ss_flags; -	compat_size_t ss_size; -}; -  struct compat_ucontext {  	compat_ulong_t	  uc_flags;  	compat_uptr_t     uc_link; @@ -56,129 +43,13 @@ struct compat_ucontext {  	sigset_t	  uc_sigmask;	/* mask last for extensibility */  }; -#define COMPAT_SI_PAD_SIZE	((SI_MAX_SIZE - 3 * sizeof(int)) / sizeof(int)) - -struct compat_siginfo { -	int si_signo; -	int si_errno; -	int si_code; - -	union { -		int _pad[COMPAT_SI_PAD_SIZE]; - -		/* kill() */ -		struct { -			unsigned int _pid;	/* sender's pid */ -			unsigned int _uid;	/* sender's uid */ -		} _kill; - -		/* POSIX.1b timers */ -		struct { -			compat_timer_t _tid;	/* timer id */ -			int _overrun;		/* overrun count */ -			compat_sigval_t _sigval;	/* same as below */ -			int _sys_private;	/* not to be passed to user */ -			int _overrun_incr;	/* amount to add to overrun */ -		} _timer; - -		/* POSIX.1b signals */ -		struct { -			unsigned int _pid;	/* sender's pid */ -			unsigned int _uid;	/* sender's uid */ -			compat_sigval_t _sigval; -		} _rt; - -		/* SIGCHLD */ -		struct { -			unsigned int _pid;	/* which child */ -			unsigned int _uid;	/* sender's uid */ -			int _status;		/* exit code */ -			compat_clock_t _utime; -			compat_clock_t _stime; -		} _sigchld; - -		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ -		struct { -			unsigned int _addr;	/* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO -			int _trapno;	/* TRAP # which caused the signal */ -#endif -		} _sigfault; - -		/* SIGPOLL */ -		struct { -			int _band;	/* POLL_IN, POLL_OUT, POLL_MSG */ -			int _fd; -		} _sigpoll; -	} _sifields; -}; -  struct compat_rt_sigframe {  	unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */  	struct compat_siginfo info;  	struct compat_ucontext uc;  }; -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act, -			     struct compat_sigaction __user *oact, -			     size_t sigsetsize) -{ -	struct k_sigaction new_sa, old_sa; -	int ret = -EINVAL; - -	/* XXX: Don't preclude handling different sized sigset_t's.  */ -	if (sigsetsize != sizeof(sigset_t)) -		goto out; - -	if (act) { -		compat_uptr_t handler, restorer; - -		if (!access_ok(VERIFY_READ, act, sizeof(*act)) || -		    __get_user(handler, &act->sa_handler) || -		    __get_user(new_sa.sa.sa_flags, &act->sa_flags) || -		    __get_user(restorer, &act->sa_restorer) || -		    __copy_from_user(&new_sa.sa.sa_mask, &act->sa_mask, -				     sizeof(sigset_t))) -			return -EFAULT; -		new_sa.sa.sa_handler = compat_ptr(handler); -		new_sa.sa.sa_restorer = compat_ptr(restorer); -	} - -	ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); - -	if (!ret && oact) { -		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || -		    __put_user(ptr_to_compat(old_sa.sa.sa_handler), -			       &oact->sa_handler) || -		    __put_user(ptr_to_compat(old_sa.sa.sa_restorer), -			       &oact->sa_restorer) || -		    __put_user(old_sa.sa.sa_flags, &oact->sa_flags) || -		    __copy_to_user(&oact->sa_mask, &old_sa.sa.sa_mask, -				   sizeof(sigset_t))) -			return -EFAULT; -	} -out: -	return ret; -} - -long compat_sys_rt_sigqueueinfo(int pid, int sig, -				struct compat_siginfo __user *uinfo) -{ -	siginfo_t info; -	int ret; -	mm_segment_t old_fs = get_fs(); - -	if (copy_siginfo_from_user32(&info, uinfo)) -		return -EFAULT; -	set_fs(KERNEL_DS); -	ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *)&info); -	set_fs(old_fs); -	return ret; -} - -int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from) +int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from)  {  	int err; @@ -256,69 +127,31 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)  	return err;  } -long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr, -			    struct compat_sigaltstack __user *uoss_ptr, -			    struct pt_regs *regs) -{ -	stack_t uss, uoss; -	int ret; -	mm_segment_t seg; - -	if (uss_ptr) { -		u32 ptr; - -		memset(&uss, 0, sizeof(stack_t)); -		if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)) || -			    __get_user(ptr, &uss_ptr->ss_sp) || -			    __get_user(uss.ss_flags, &uss_ptr->ss_flags) || -			    __get_user(uss.ss_size, &uss_ptr->ss_size)) -			return -EFAULT; -		uss.ss_sp = compat_ptr(ptr); -	} -	seg = get_fs(); -	set_fs(KERNEL_DS); -	ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL, -			     (stack_t __user __force *)&uoss, -			     (unsigned long)compat_ptr(regs->sp)); -	set_fs(seg); -	if (ret >= 0 && uoss_ptr)  { -		if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) || -		    __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) || -		    __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) || -		    __put_user(uoss.ss_size, &uoss_ptr->ss_size)) -			ret = -EFAULT; -	} -	return ret; -} - -long compat_sys_rt_sigreturn(struct pt_regs *regs) +/* The assembly shim for this function arranges to ignore the return value. */ +long compat_sys_rt_sigreturn(void)  { +	struct pt_regs *regs = current_pt_regs();  	struct compat_rt_sigframe __user *frame =  		(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);  	sigset_t set; -	long r0;  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))  		goto badframe;  	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))  		goto badframe; -	sigdelsetmask(&set, ~_BLOCKABLE); -	spin_lock_irq(¤t->sighand->siglock); -	current->blocked = set; -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); +	set_current_blocked(&set); -	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0)) +	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))  		goto badframe; -	if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0) +	if (compat_restore_altstack(&frame->uc.uc_stack))  		goto badframe; -	return r0; +	return 0;  badframe: -	force_sig(SIGSEGV, current); +	signal_fault("bad sigreturn frame", regs, frame, 0);  	return 0;  } @@ -389,17 +222,13 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	err |= __clear_user(&frame->save_area, sizeof(frame->save_area));  	err |= __put_user(0, &frame->uc.uc_flags);  	err |= __put_user(0, &frame->uc.uc_link); -	err |= __put_user(ptr_to_compat((void *)(current->sas_ss_sp)), -			  &frame->uc.uc_stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->sp), -			  &frame->uc.uc_stack.ss_flags); -	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); +	err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp);  	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);  	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));  	if (err)  		goto give_sigsegv; -	restorer = VDSO_BASE; +	restorer = VDSO_SYM(&__vdso_rt_sigreturn);  	if (ka->sa.sa_flags & SA_RESTORER)  		restorer = ptr_to_compat_reg(ka->sa.sa_restorer); @@ -407,31 +236,20 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	 * Set up registers for signal handler.  	 * Registers that we don't modify keep the value they had from  	 * user-space at the time we took the signal. +	 * We always pass siginfo and mcontext, regardless of SA_SIGINFO, +	 * since some things rely on this (e.g. glibc's debug/segfault.c).  	 */  	regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);  	regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */  	regs->sp = ptr_to_compat_reg(frame);  	regs->lr = restorer;  	regs->regs[0] = (unsigned long) usig; - -	if (ka->sa.sa_flags & SA_SIGINFO) { -		/* Need extra arguments, so mark to restore caller-saves. */ -		regs->regs[1] = ptr_to_compat_reg(&frame->info); -		regs->regs[2] = ptr_to_compat_reg(&frame->uc); -		regs->flags |= PT_FLAGS_CALLER_SAVES; -	} - -	/* -	 * Notify any tracer that was single-stepping it. -	 * The tracer may want to single-step inside the -	 * handler too. -	 */ -	if (test_thread_flag(TIF_SINGLESTEP)) -		ptrace_notify(SIGTRAP); - +	regs->regs[1] = ptr_to_compat_reg(&frame->info); +	regs->regs[2] = ptr_to_compat_reg(&frame->uc); +	regs->flags |= PT_FLAGS_CALLER_SAVES;  	return 0;  give_sigsegv: -	force_sigsegv(sig, current); +	signal_fault("bad setup frame", regs, frame, sig);  	return -EFAULT;  }  | 
