diff options
Diffstat (limited to 'arch/s390/kernel/compat_signal.c')
| -rw-r--r-- | arch/s390/kernel/compat_signal.c | 376 | 
1 files changed, 104 insertions, 272 deletions
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index eee999853a7..f204d692036 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -1,7 +1,5 @@  /* - *  arch/s390/kernel/compat_signal.c - * - *    Copyright (C) IBM Corp. 2000,2006 + *    Copyright IBM Corp. 2000, 2006   *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)   *               Gerhard Tonn (ton@de.ibm.com)                     * @@ -27,12 +25,11 @@  #include <asm/ucontext.h>  #include <asm/uaccess.h>  #include <asm/lowcore.h> +#include <asm/switch_to.h>  #include "compat_linux.h"  #include "compat_ptrace.h"  #include "entry.h" -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) -  typedef struct   {  	__u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; @@ -52,13 +49,10 @@ typedef struct  	__u32 gprs_high[NUM_GPRS];  } rt_sigframe32; -int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) +int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)  {  	int err; -	if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) -		return -EFAULT; -  	/* If you change siginfo_t structure, please be sure  	   this code is fixed accordingly.  	   It should never copy any pad contained in the structure @@ -105,7 +99,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)  			break;  		}  	} -	return err; +	return err ? -EFAULT : 0;  }  int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) @@ -113,9 +107,6 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)  	int err;  	u32 tmp; -	if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t))) -		return -EFAULT; -  	err = __get_user(to->si_signo, &from->si_signo);  	err |= __get_user(to->si_errno, &from->si_errno);  	err |= __get_user(to->si_code, &from->si_code); @@ -141,7 +132,8 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)  			break;  		case __SI_FAULT >> 16:  			err |= __get_user(tmp, &from->si_addr); -			to->si_addr = (void __user *)(u64) (tmp & PSW32_ADDR_INSN); +			to->si_addr = (void __force __user *) +				(u64) (tmp & PSW32_ADDR_INSN);  			break;  		case __SI_POLL >> 16:  			err |= __get_user(to->si_band, &from->si_band); @@ -156,193 +148,72 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)  			break;  		}  	} -	return err; -} - -asmlinkage long -sys32_sigaction(int sig, const struct old_sigaction32 __user *act, -		 struct old_sigaction32 __user *oact) -{ -        struct k_sigaction new_ka, old_ka; -	unsigned long sa_handler, sa_restorer; -        int ret; - -        if (act) { -		compat_old_sigset_t mask; -		if (!access_ok(VERIFY_READ, act, sizeof(*act)) || -		    __get_user(sa_handler, &act->sa_handler) || -		    __get_user(sa_restorer, &act->sa_restorer) || -		    __get_user(new_ka.sa.sa_flags, &act->sa_flags) || -		    __get_user(mask, &act->sa_mask)) -			return -EFAULT; -		new_ka.sa.sa_handler = (__sighandler_t) sa_handler; -		new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer; -		siginitset(&new_ka.sa.sa_mask, mask); -        } - -        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - -	if (!ret && oact) { -		sa_handler = (unsigned long) old_ka.sa.sa_handler; -		sa_restorer = (unsigned long) old_ka.sa.sa_restorer; -		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || -		    __put_user(sa_handler, &oact->sa_handler) || -		    __put_user(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; -        } - -	return ret; -} - -asmlinkage long -sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, -	   struct sigaction32 __user *oact,  size_t sigsetsize) -{ -	struct k_sigaction new_ka, old_ka; -	unsigned long sa_handler; -	int ret; -	compat_sigset_t set32; - -	/* XXX: Don't preclude handling different sized sigset_t's.  */ -	if (sigsetsize != sizeof(compat_sigset_t)) -		return -EINVAL; - -	if (act) { -		ret = get_user(sa_handler, &act->sa_handler); -		ret |= __copy_from_user(&set32, &act->sa_mask, -					sizeof(compat_sigset_t)); -		switch (_NSIG_WORDS) { -		case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] -				| (((long)set32.sig[7]) << 32); -		case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] -				| (((long)set32.sig[5]) << 32); -		case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] -				| (((long)set32.sig[3]) << 32); -		case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] -				| (((long)set32.sig[1]) << 32); -		} -		ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); -		 -		if (ret) -			return -EFAULT; -		new_ka.sa.sa_handler = (__sighandler_t) sa_handler; -	} - -	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - -	if (!ret && oact) { -		switch (_NSIG_WORDS) { -		case 4: -			set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); -			set32.sig[6] = old_ka.sa.sa_mask.sig[3]; -		case 3: -			set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); -			set32.sig[4] = old_ka.sa.sa_mask.sig[2]; -		case 2: -			set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); -			set32.sig[2] = old_ka.sa.sa_mask.sig[1]; -		case 1: -			set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); -			set32.sig[0] = old_ka.sa.sa_mask.sig[0]; -		} -		ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler); -		ret |= __copy_to_user(&oact->sa_mask, &set32, -				      sizeof(compat_sigset_t)); -		ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); -	} - -	return ret; -} - -asmlinkage long -sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss) -{ -	struct pt_regs *regs = task_pt_regs(current); -	stack_t kss, koss; -	unsigned long ss_sp; -	int ret, err = 0; -	mm_segment_t old_fs = get_fs(); - -	if (uss) { -		if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) -			return -EFAULT; -		err |= __get_user(ss_sp, &uss->ss_sp); -		err |= __get_user(kss.ss_size, &uss->ss_size); -		err |= __get_user(kss.ss_flags, &uss->ss_flags); -		if (err) -			return -EFAULT; -		kss.ss_sp = (void __user *) ss_sp; -	} - -	set_fs (KERNEL_DS); -	ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL), -			     (stack_t __force __user *) (uoss ? &koss : NULL), -			     regs->gprs[15]); -	set_fs (old_fs); - -	if (!ret && uoss) { -		if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) -			return -EFAULT; -		ss_sp = (unsigned long) koss.ss_sp; -		err |= __put_user(ss_sp, &uoss->ss_sp); -		err |= __put_user(koss.ss_size, &uoss->ss_size); -		err |= __put_user(koss.ss_flags, &uoss->ss_flags); -		if (err) -			return -EFAULT; -	} -	return ret; +	return err ? -EFAULT : 0;  }  static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)  { -	_s390_regs_common32 regs32; -	int err, i; +	_sigregs32 user_sregs; +	int i; -	regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits, -					   (__u32)(regs->psw.mask >> 32)); -	regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr; +	user_sregs.regs.psw.mask = (__u32)(regs->psw.mask >> 32); +	user_sregs.regs.psw.mask &= PSW32_MASK_USER | PSW32_MASK_RI; +	user_sregs.regs.psw.mask |= PSW32_USER_BITS; +	user_sregs.regs.psw.addr = (__u32) regs->psw.addr | +		(__u32)(regs->psw.mask & PSW_MASK_BA);  	for (i = 0; i < NUM_GPRS; i++) -		regs32.gprs[i] = (__u32) regs->gprs[i]; +		user_sregs.regs.gprs[i] = (__u32) regs->gprs[i];  	save_access_regs(current->thread.acrs); -	memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs)); -	err = __copy_to_user(&sregs->regs, ®s32, sizeof(regs32)); -	if (err) -		return err; -	save_fp_regs(¤t->thread.fp_regs); -	/* s390_fp_regs and _s390_fp_regs32 are the same ! */ -	return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs, -			      sizeof(_s390_fp_regs32)); +	memcpy(&user_sregs.regs.acrs, current->thread.acrs, +	       sizeof(user_sregs.regs.acrs)); +	save_fp_ctl(¤t->thread.fp_regs.fpc); +	save_fp_regs(current->thread.fp_regs.fprs); +	memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, +	       sizeof(user_sregs.fpregs)); +	if (__copy_to_user(sregs, &user_sregs, sizeof(_sigregs32))) +		return -EFAULT; +	return 0;  }  static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)  { -	_s390_regs_common32 regs32; -	int err, i; +	_sigregs32 user_sregs; +	int i;  	/* Alwys make any pending restarted system call return -EINTR */  	current_thread_info()->restart_block.fn = do_no_restart_syscall; -	err = __copy_from_user(®s32, &sregs->regs, sizeof(regs32)); -	if (err) -		return err; -	regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask, -				        (__u64)regs32.psw.mask << 32); -	regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); +	if (__copy_from_user(&user_sregs, &sregs->regs, sizeof(user_sregs))) +		return -EFAULT; + +	if (!is_ri_task(current) && (user_sregs.regs.psw.mask & PSW32_MASK_RI)) +		return -EINVAL; + +	/* Loading the floating-point-control word can fail. Do that first. */ +	if (restore_fp_ctl(&user_sregs.fpregs.fpc)) +		return -EINVAL; + +	/* Use regs->psw.mask instead of PSW_USER_BITS to preserve PER bit. */ +	regs->psw.mask = (regs->psw.mask & ~(PSW_MASK_USER | PSW_MASK_RI)) | +		(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_USER) << 32 | +		(__u64)(user_sregs.regs.psw.mask & PSW32_MASK_RI) << 32 | +		(__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_AMODE); +	/* Check for invalid user address space control. */ +	if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_HOME) +		regs->psw.mask = PSW_ASC_PRIMARY | +			(regs->psw.mask & ~PSW_MASK_ASC); +	regs->psw.addr = (__u64)(user_sregs.regs.psw.addr & PSW32_ADDR_INSN);  	for (i = 0; i < NUM_GPRS; i++) -		regs->gprs[i] = (__u64) regs32.gprs[i]; -	memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs)); +		regs->gprs[i] = (__u64) user_sregs.regs.gprs[i]; +	memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, +	       sizeof(current->thread.acrs));  	restore_access_regs(current->thread.acrs); -	err = __copy_from_user(¤t->thread.fp_regs, &sregs->fpregs, -			       sizeof(_s390_fp_regs32)); -	current->thread.fp_regs.fpc &= FPC_VALID_MASK; -	if (err) -		return err; +	memcpy(¤t->thread.fp_regs, &user_sregs.fpregs, +	       sizeof(current->thread.fp_regs)); -	restore_fp_regs(¤t->thread.fp_regs); -	regs->svcnr = 0;	/* disable syscall checks */ +	restore_fp_regs(current->thread.fp_regs.fprs); +	clear_pt_regs_flag(regs, PIF_SYSCALL); /* No longer in a system call */  	return 0;  } @@ -353,91 +224,58 @@ static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)  	for (i = 0; i < NUM_GPRS; i++)  		gprs_high[i] = regs->gprs[i] >> 32; - -	return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high)); +	if (__copy_to_user(uregs, &gprs_high, sizeof(gprs_high))) +		return -EFAULT; +	return 0;  }  static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)  {  	__u32 gprs_high[NUM_GPRS]; -	int err, i; +	int i; -	err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high)); -	if (err) -		return err; +	if (__copy_from_user(&gprs_high, uregs, sizeof(gprs_high))) +		return -EFAULT;  	for (i = 0; i < NUM_GPRS; i++)  		*(__u32 *)®s->gprs[i] = gprs_high[i];  	return 0;  } -asmlinkage long sys32_sigreturn(void) +COMPAT_SYSCALL_DEFINE0(sigreturn)  {  	struct pt_regs *regs = task_pt_regs(current);  	sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15];  	sigset_t set; -	if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) -		goto badframe;  	if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32))  		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_sigregs32(regs, &frame->sregs))  		goto badframe;  	if (restore_sigregs_gprs_high(regs, frame->gprs_high))  		goto badframe; -  	return regs->gprs[2]; -  badframe:  	force_sig(SIGSEGV, current);  	return 0;  } -asmlinkage long sys32_rt_sigreturn(void) +COMPAT_SYSCALL_DEFINE0(rt_sigreturn)  {  	struct pt_regs *regs = task_pt_regs(current);  	rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15];  	sigset_t set; -	stack_t st; -	__u32 ss_sp; -	int err; -	mm_segment_t old_fs = get_fs(); -	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_sigregs32(regs, &frame->uc.uc_mcontext))  		goto badframe;  	if (restore_sigregs_gprs_high(regs, frame->gprs_high))  		goto badframe; - -	err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp); -	st.ss_sp = compat_ptr(ss_sp); -	err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size); -	err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags); -	if (err) +	if (compat_restore_altstack(&frame->uc.uc_stack))  		goto badframe;  - -	set_fs (KERNEL_DS); -	do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]); -	set_fs (old_fs); -  	return regs->gprs[2]; -  badframe:  	force_sig(SIGSEGV, current);  	return 0; @@ -469,13 +307,6 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)  			sp = current->sas_ss_sp + current->sas_ss_size;  	} -	/* This is the legacy signal stack switching. */ -	else if (!user_mode(regs) && -		 !(ka->sa.sa_flags & SA_RESTORER) && -		 ka->sa.sa_restorer) { -		sp = (unsigned long) ka->sa.sa_restorer; -	} -  	return (void __user *)((sp - frame_size) & -8ul);  } @@ -493,8 +324,6 @@ static int setup_frame32(int sig, struct k_sigaction *ka,  			sigset_t *set, struct pt_regs * regs)  {  	sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32)); -	if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32))) -		goto give_sigsegv;  	if (frame == (void __user *) -1UL)  		goto give_sigsegv; @@ -512,11 +341,11 @@ static int setup_frame32(int sig, struct k_sigaction *ka,  	/* Set up to return from userspace.  If provided, use a stub  	   already in userspace.  */  	if (ka->sa.sa_flags & SA_RESTORER) { -		regs->gprs[14] = (__u64) ka->sa.sa_restorer; +		regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE;  	} else { -		regs->gprs[14] = (__u64) frame->retcode; +		regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;  		if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, -		               (u16 __user *)(frame->retcode))) +			       (u16 __force __user *)(frame->retcode)))  			goto give_sigsegv;          } @@ -525,19 +354,28 @@ static int setup_frame32(int sig, struct k_sigaction *ka,  		goto give_sigsegv;  	/* Set up registers for signal handler */ -	regs->gprs[15] = (__u64) frame; -	regs->psw.addr = (__u64) ka->sa.sa_handler; +	regs->gprs[15] = (__force __u64) frame; +	/* Force 31 bit amode and default user address space control. */ +	regs->psw.mask = PSW_MASK_BA | +		(PSW_USER_BITS & PSW_MASK_ASC) | +		(regs->psw.mask & ~PSW_MASK_ASC); +	regs->psw.addr = (__force __u64) ka->sa.sa_handler;  	regs->gprs[2] = map_signal(sig); -	regs->gprs[3] = (__u64) &frame->sc; +	regs->gprs[3] = (__force __u64) &frame->sc;  	/* We forgot to include these in the sigcontext.  	   To avoid breaking binary compatibility, they are passed as args. */ -	regs->gprs[4] = current->thread.trap_no; -	regs->gprs[5] = current->thread.prot_addr; +	if (sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || +	    sig == SIGTRAP || sig == SIGFPE) { +		/* set extra registers only for synchronous signals */ +		regs->gprs[4] = regs->int_code & 127; +		regs->gprs[5] = regs->int_parm_long; +		regs->gprs[6] = task_thread_info(current)->last_break; +	}  	/* Place signal number on stack to allow backtrace from handler.  */ -	if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) +	if (__put_user(regs->gprs[2], (int __force __user *) &frame->signo))  		goto give_sigsegv;  	return 0; @@ -551,8 +389,6 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,  {  	int err = 0;  	rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); -	if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32))) -		goto give_sigsegv;  	if (frame == (void __user *) -1UL)  		goto give_sigsegv; @@ -563,10 +399,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,  	/* Create the ucontext.  */  	err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);  	err |= __put_user(0, &frame->uc.uc_link); -	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); -	err |= __put_user(sas_ss_flags(regs->gprs[15]), -	                  &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->gprs[15]);  	err |= save_sigregs32(regs, &frame->uc.uc_mcontext);  	err |= save_sigregs_gprs_high(regs, frame->gprs_high);  	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); @@ -576,24 +409,30 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,  	/* Set up to return from userspace.  If provided, use a stub  	   already in userspace.  */  	if (ka->sa.sa_flags & SA_RESTORER) { -		regs->gprs[14] = (__u64) ka->sa.sa_restorer; +		regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE;  	} else { -		regs->gprs[14] = (__u64) frame->retcode; -		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, -		                  (u16 __user *)(frame->retcode)); +		regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE; +		if (__put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, +			       (u16 __force __user *)(frame->retcode))) +			goto give_sigsegv;  	}  	/* Set up backchain. */ -	if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) +	if (__put_user(regs->gprs[15], (unsigned int __force __user *) frame))  		goto give_sigsegv;  	/* Set up registers for signal handler */ -	regs->gprs[15] = (__u64) frame; -	regs->psw.addr = (__u64) ka->sa.sa_handler; +	regs->gprs[15] = (__force __u64) frame; +	/* Force 31 bit amode and default user address space control. */ +	regs->psw.mask = PSW_MASK_BA | +		(PSW_USER_BITS & PSW_MASK_ASC) | +		(regs->psw.mask & ~PSW_MASK_ASC); +	regs->psw.addr = (__u64 __force) ka->sa.sa_handler;  	regs->gprs[2] = map_signal(sig); -	regs->gprs[3] = (__u64) &frame->info; -	regs->gprs[4] = (__u64) &frame->uc; +	regs->gprs[3] = (__force __u64) &frame->info; +	regs->gprs[4] = (__force __u64) &frame->uc; +	regs->gprs[5] = task_thread_info(current)->last_break;  	return 0;  give_sigsegv: @@ -605,9 +444,8 @@ give_sigsegv:   * OK, we're invoking a handler   */	 -int -handle_signal32(unsigned long sig, struct k_sigaction *ka, -		siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) +void handle_signal32(unsigned long sig, struct k_sigaction *ka, +		    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)  {  	int ret; @@ -616,15 +454,9 @@ handle_signal32(unsigned long sig, struct k_sigaction *ka,  		ret = setup_rt_frame32(sig, ka, info, oldset, regs);  	else  		ret = setup_frame32(sig, ka, oldset, regs); - -	if (ret == 0) { -		spin_lock_irq(¤t->sighand->siglock); -		sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); -		if (!(ka->sa.sa_flags & SA_NODEFER)) -			sigaddset(¤t->blocked,sig); -		recalc_sigpending(); -		spin_unlock_irq(¤t->sighand->siglock); -	} -	return ret; +	if (ret) +		return; +	signal_delivered(sig, info, ka, regs, +				 test_thread_flag(TIF_SINGLE_STEP));  }  | 
