diff options
Diffstat (limited to 'arch/arc/kernel/signal.c')
| -rw-r--r-- | arch/arc/kernel/signal.c | 38 | 
1 files changed, 19 insertions, 19 deletions
diff --git a/arch/arc/kernel/signal.c b/arch/arc/kernel/signal.c index 114234e83caa..2251fb4bbfd7 100644 --- a/arch/arc/kernel/signal.c +++ b/arch/arc/kernel/signal.c @@ -67,7 +67,7 @@ stash_usr_regs(struct rt_sigframe __user *sf, struct pt_regs *regs,  	       sigset_t *set)  {  	int err; -	err = __copy_to_user(&(sf->uc.uc_mcontext.regs), regs, +	err = __copy_to_user(&(sf->uc.uc_mcontext.regs.scratch), regs,  			     sizeof(sf->uc.uc_mcontext.regs.scratch));  	err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(sigset_t)); @@ -83,7 +83,7 @@ static int restore_usr_regs(struct pt_regs *regs, struct rt_sigframe __user *sf)  	if (!err)  		set_current_blocked(&set); -	err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs), +	err |= __copy_from_user(regs, &(sf->uc.uc_mcontext.regs.scratch),  				sizeof(sf->uc.uc_mcontext.regs.scratch));  	return err; @@ -131,6 +131,15 @@ SYSCALL_DEFINE0(rt_sigreturn)  	/* Don't restart from sigreturn */  	syscall_wont_restart(regs); +	/* +	 * Ensure that sigreturn always returns to user mode (in case the +	 * regs saved on user stack got fudged between save and sigreturn) +	 * Otherwise it is easy to panic the kernel with a custom +	 * signal handler and/or restorer which clobberes the status32/ret +	 * to return to a bogus location in kernel mode. +	 */ +	regs->status32 |= STATUS_U_MASK; +  	return regs->r0;  badframe: @@ -162,18 +171,6 @@ static inline void __user *get_sigframe(struct ksignal *ksig,  	return frame;  } -/* - * translate the signal - */ -static inline int map_sig(int sig) -{ -	struct thread_info *thread = current_thread_info(); -	if (thread->exec_domain && thread->exec_domain->signal_invmap -	    && sig < 32) -		sig = thread->exec_domain->signal_invmap[sig]; -	return sig; -} -  static int  setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)  { @@ -222,15 +219,18 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)  		return err;  	/* #1 arg to the user Signal handler */ -	regs->r0 = map_sig(ksig->sig); +	regs->r0 = ksig->sig;  	/* setup PC of user space signal handler */  	regs->ret = (unsigned long)ksig->ka.sa.sa_handler;  	/*  	 * handler returns using sigreturn stub provided already by userpsace +	 * If not, nuke the process right away  	 */ -	BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER)); +	if(!(ksig->ka.sa.sa_flags & SA_RESTORER)) +		return 1; +  	regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;  	/* User Stack for signal handler will be above the frame just carved */ @@ -296,12 +296,12 @@ static void  handle_signal(struct ksignal *ksig, struct pt_regs *regs)  {  	sigset_t *oldset = sigmask_to_save(); -	int ret; +	int failed;  	/* Set up the stack frame */ -	ret = setup_rt_frame(ksig, oldset, regs); +	failed = setup_rt_frame(ksig, oldset, regs); -	signal_setup_done(ret, ksig, 0); +	signal_setup_done(failed, ksig, 0);  }  void do_signal(struct pt_regs *regs)  |