diff options
Diffstat (limited to 'arch/arm/kernel/signal.c')
| -rw-r--r-- | arch/arm/kernel/signal.c | 133 | 
1 files changed, 22 insertions, 111 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index d68d1b69468..fd2392a17ac 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -22,14 +22,11 @@  #include "signal.h" -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -  /*   * For ARM syscalls, we encode the syscall number into the instruction.   */  #define SWI_SYS_SIGRETURN	(0xef000000|(__NR_sigreturn)|(__NR_OABI_SYSCALL_BASE))  #define SWI_SYS_RT_SIGRETURN	(0xef000000|(__NR_rt_sigreturn)|(__NR_OABI_SYSCALL_BASE)) -#define SWI_SYS_RESTART		(0xef000000|__NR_restart_syscall|__NR_OABI_SYSCALL_BASE)  /*   * With EABI, the syscall number has to be loaded into r7. @@ -50,34 +47,13 @@ const unsigned long sigreturn_codes[7] = {  };  /* - * Either we support OABI only, or we have EABI with the OABI - * compat layer enabled.  In the later case we don't know if - * user space is EABI or not, and if not we must not clobber r7. - * Always using the OABI syscall solves that issue and works for - * all those cases. - */ -const unsigned long syscall_restart_code[2] = { -	SWI_SYS_RESTART,	/* swi	__NR_restart_syscall */ -	0xe49df004,		/* ldr	pc, [sp], #4 */ -}; - -/*   * atomically swap in the new signal mask, and wait for a signal.   */  asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)  {  	sigset_t blocked; - -	current->saved_sigmask = current->blocked; - -	mask &= _BLOCKABLE;  	siginitset(&blocked, mask); -	set_current_blocked(&blocked); - -	current->state = TASK_INTERRUPTIBLE; -	schedule(); -	set_restore_sigmask(); -	return -ERESTARTNOHAND; +	return sigsuspend(&blocked);  }  asmlinkage int  @@ -91,10 +67,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,  		old_sigset_t mask;  		if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||  		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) || -		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) +		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || +		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) || +		    __get_user(mask, &act->sa_mask))  			return -EFAULT; -		__get_user(new_ka.sa.sa_flags, &act->sa_flags); -		__get_user(mask, &act->sa_mask);  		siginitset(&new_ka.sa.sa_mask, mask);  	} @@ -103,10 +79,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,  	if (!ret && oact) {  		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||  		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || -		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) +		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || +		    __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || +		    __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))  			return -EFAULT; -		__put_user(old_ka.sa.sa_flags, &oact->sa_flags); -		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);  	}  	return ret; @@ -232,10 +208,8 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)  	int err;  	err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); -	if (err == 0) { -		sigdelsetmask(&set, ~_BLOCKABLE); +	if (err == 0)  		set_current_blocked(&set); -	}  	__get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);  	__get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err); @@ -550,13 +524,13 @@ setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,  /*   * OK, we're invoking a handler   */	 -static int +static void  handle_signal(unsigned long sig, struct k_sigaction *ka, -	      siginfo_t *info, sigset_t *oldset, -	      struct pt_regs * regs) +	      siginfo_t *info, struct pt_regs *regs)  {  	struct thread_info *thread = current_thread_info();  	struct task_struct *tsk = current; +	sigset_t *oldset = sigmask_to_save();  	int usig = sig;  	int ret; @@ -581,15 +555,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,  	if (ret != 0) {  		force_sigsegv(sig, tsk); -		return ret; +		return;  	} - -	/* -	 * Block the signal if we were successful. -	 */ -	block_sigmask(ka, sig); - -	return 0; +	signal_delivered(sig, info, ka, regs, 0);  }  /* @@ -609,15 +577,6 @@ static void do_signal(struct pt_regs *regs, int syscall)  	int signr;  	/* -	 * We want the common case to go fast, which -	 * is why we may in certain cases get here from -	 * kernel mode. Just return without doing anything -	 * if so. -	 */ -	if (!user_mode(regs)) -		return; - -	/*  	 * If we were from a system call, check for system call restarting...  	 */  	if (syscall) { @@ -633,58 +592,39 @@ static void do_signal(struct pt_regs *regs, int syscall)  		case -ERESTARTNOHAND:  		case -ERESTARTSYS:  		case -ERESTARTNOINTR: +		case -ERESTART_RESTARTBLOCK:  			regs->ARM_r0 = regs->ARM_ORIG_r0;  			regs->ARM_pc = restart_addr;  			break; -		case -ERESTART_RESTARTBLOCK: -			regs->ARM_r0 = -EINTR; -			break;  		}  	} -	if (try_to_freeze()) -		goto no_signal; -  	/*  	 * Get the signal to deliver.  When running under ptrace, at this  	 * point the debugger may change all our registers ...  	 */  	signr = get_signal_to_deliver(&info, &ka, regs, NULL);  	if (signr > 0) { -		sigset_t *oldset; -  		/*  		 * Depending on the signal settings we may need to revert the  		 * decision to restart the system call.  But skip this if a  		 * debugger has chosen to restart at a different PC.  		 */  		if (regs->ARM_pc == restart_addr) { -			if (retval == -ERESTARTNOHAND +			if (retval == -ERESTARTNOHAND || +			    retval == -ERESTART_RESTARTBLOCK  			    || (retval == -ERESTARTSYS  				&& !(ka.sa.sa_flags & SA_RESTART))) {  				regs->ARM_r0 = -EINTR;  				regs->ARM_pc = continue_addr;  			} +			clear_thread_flag(TIF_SYSCALL_RESTARTSYS);  		} -		if (test_thread_flag(TIF_RESTORE_SIGMASK)) -			oldset = ¤t->saved_sigmask; -		else -			oldset = ¤t->blocked; -		if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { -			/* -			 * A signal was successfully delivered; the saved -			 * sigmask will have been stored in the signal frame, -			 * and will be restored by sigreturn, so we can simply -			 * clear the TIF_RESTORE_SIGMASK flag. -			 */ -			if (test_thread_flag(TIF_RESTORE_SIGMASK)) -				clear_thread_flag(TIF_RESTORE_SIGMASK); -		} +		handle_signal(signr, &ka, &info, regs);  		return;  	} - no_signal:  	if (syscall) {  		/*  		 * Handle restarting a different system call.  As above, @@ -692,38 +632,11 @@ static void do_signal(struct pt_regs *regs, int syscall)  		 * ignore the restart.  		 */  		if (retval == -ERESTART_RESTARTBLOCK -		    && regs->ARM_pc == continue_addr) { -			if (thumb_mode(regs)) { -				regs->ARM_r7 = __NR_restart_syscall - __NR_SYSCALL_BASE; -				regs->ARM_pc -= 2; -			} else { -#if defined(CONFIG_AEABI) && !defined(CONFIG_OABI_COMPAT) -				regs->ARM_r7 = __NR_restart_syscall; -				regs->ARM_pc -= 4; -#else -				u32 __user *usp; - -				regs->ARM_sp -= 4; -				usp = (u32 __user *)regs->ARM_sp; - -				if (put_user(regs->ARM_pc, usp) == 0) { -					regs->ARM_pc = KERN_RESTART_CODE; -				} else { -					regs->ARM_sp += 4; -					force_sigsegv(0, current); -				} -#endif -			} -		} - -		/* If there's no signal to deliver, we just put the saved sigmask -		 * back. -		 */ -		if (test_thread_flag(TIF_RESTORE_SIGMASK)) { -			clear_thread_flag(TIF_RESTORE_SIGMASK); -			sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -		} +		    && regs->ARM_pc == restart_addr) +			set_thread_flag(TIF_SYSCALL_RESTARTSYS);  	} + +	restore_saved_sigmask();  }  asmlinkage void @@ -735,7 +648,5 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)  	if (thread_flags & _TIF_NOTIFY_RESUME) {  		clear_thread_flag(TIF_NOTIFY_RESUME);  		tracehook_notify_resume(regs); -		if (current->replacement_session_keyring) -			key_replace_session_keyring();  	}  }  |