diff options
Diffstat (limited to 'arch/x86/kernel/signal.c')
| -rw-r--r-- | arch/x86/kernel/signal.c | 461 | 
1 files changed, 194 insertions, 267 deletions
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4fd173cd8e5..2851d63c120 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -6,30 +6,36 @@   *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes   *  2000-2002   x86-64 support by Andi Kleen   */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/sched.h>  #include <linux/mm.h>  #include <linux/smp.h>  #include <linux/kernel.h> -#include <linux/signal.h>  #include <linux/errno.h>  #include <linux/wait.h> -#include <linux/ptrace.h>  #include <linux/tracehook.h>  #include <linux/unistd.h>  #include <linux/stddef.h>  #include <linux/personality.h>  #include <linux/uaccess.h>  #include <linux/user-return-notifier.h> +#include <linux/uprobes.h> +#include <linux/context_tracking.h>  #include <asm/processor.h>  #include <asm/ucontext.h>  #include <asm/i387.h> +#include <asm/fpu-internal.h>  #include <asm/vdso.h>  #include <asm/mce.h> +#include <asm/sighandling.h>  #ifdef CONFIG_X86_64  #include <asm/proto.h>  #include <asm/ia32_unistd.h> +#include <asm/sys_ia32.h>  #endif /* CONFIG_X86_64 */  #include <asm/syscall.h> @@ -37,19 +43,6 @@  #include <asm/sigframe.h> -#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) - -#define __FIX_EFLAGS	(X86_EFLAGS_AC | X86_EFLAGS_OF | \ -			 X86_EFLAGS_DF | X86_EFLAGS_TF | X86_EFLAGS_SF | \ -			 X86_EFLAGS_ZF | X86_EFLAGS_AF | X86_EFLAGS_PF | \ -			 X86_EFLAGS_CF) - -#ifdef CONFIG_X86_32 -# define FIX_EFLAGS	(__FIX_EFLAGS | X86_EFLAGS_RF) -#else -# define FIX_EFLAGS	__FIX_EFLAGS -#endif -  #define COPY(x)			do {			\  	get_user_ex(regs->x, &sc->x);			\  } while (0) @@ -68,9 +61,8 @@  	regs->seg = GET_SEG(seg) | 3;			\  } while (0) -static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, -		   unsigned long *pax) +int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, +		       unsigned long *pax)  {  	void __user *buf;  	unsigned int tmpflags; @@ -117,17 +109,17 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,  		regs->orig_ax = -1;		/* disable syscall checks */  		get_user_ex(buf, &sc->fpstate); -		err |= restore_i387_xstate(buf);  		get_user_ex(*pax, &sc->ax);  	} get_user_catch(err); +	err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32)); +  	return err;  } -static int -setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, -		 struct pt_regs *regs, unsigned long mask) +int setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate, +		     struct pt_regs *regs, unsigned long mask)  {  	int err = 0; @@ -159,7 +151,7 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,  		put_user_ex(regs->r15, &sc->r15);  #endif /* CONFIG_X86_64 */ -		put_user_ex(current->thread.trap_no, &sc->trapno); +		put_user_ex(current->thread.trap_nr, &sc->trapno);  		put_user_ex(current->thread.error_code, &sc->err);  		put_user_ex(regs->ip, &sc->ip);  #ifdef CONFIG_X86_32 @@ -210,35 +202,32 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,  	     void __user **fpstate)  {  	/* Default to using normal stack */ +	unsigned long math_size = 0;  	unsigned long sp = regs->sp; +	unsigned long buf_fx = 0;  	int onsigstack = on_sig_stack(sp); -#ifdef CONFIG_X86_64  	/* redzone */ -	sp -= 128; -#endif /* CONFIG_X86_64 */ +	if (config_enabled(CONFIG_X86_64)) +		sp -= 128;  	if (!onsigstack) {  		/* This is the X/Open sanctioned signal stack switching.  */  		if (ka->sa.sa_flags & SA_ONSTACK) {  			if (current->sas_ss_size)  				sp = current->sas_ss_sp + current->sas_ss_size; -		} else { -#ifdef CONFIG_X86_32 -			/* This is the legacy signal stack switching. */ -			if ((regs->ss & 0xffff) != __USER_DS && -				!(ka->sa.sa_flags & SA_RESTORER) && -					ka->sa.sa_restorer) +		} else if (config_enabled(CONFIG_X86_32) && +			   (regs->ss & 0xffff) != __USER_DS && +			   !(ka->sa.sa_flags & SA_RESTORER) && +			   ka->sa.sa_restorer) { +				/* This is the legacy signal stack switching. */  				sp = (unsigned long) ka->sa.sa_restorer; -#endif /* CONFIG_X86_32 */  		}  	}  	if (used_math()) { -		sp -= sig_xstate_size; -#ifdef CONFIG_X86_64 -		sp = round_down(sp, 64); -#endif /* CONFIG_X86_64 */ +		sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32), +				     &buf_fx, &math_size);  		*fpstate = (void __user *)sp;  	} @@ -251,8 +240,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,  	if (onsigstack && !likely(on_sig_stack(sp)))  		return (void __user *)-1L; -	/* save i387 state */ -	if (used_math() && save_i387_xstate(*fpstate) < 0) +	/* save i387 and extended state */ +	if (used_math() && +	    save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0)  		return (void __user *)-1L;  	return (void __user *)sp; @@ -282,7 +272,7 @@ static const struct {  };  static int -__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, +__setup_frame(int sig, struct ksignal *ksig, sigset_t *set,  	      struct pt_regs *regs)  {  	struct sigframe __user *frame; @@ -290,7 +280,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,  	int err = 0;  	void __user *fpstate = NULL; -	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); +	frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);  	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))  		return -EFAULT; @@ -308,11 +298,12 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,  	}  	if (current->mm->context.vdso) -		restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); +		restorer = current->mm->context.vdso + +			selected_vdso32->sym___kernel_sigreturn;  	else  		restorer = &frame->retcode; -	if (ka->sa.sa_flags & SA_RESTORER) -		restorer = ka->sa.sa_restorer; +	if (ksig->ka.sa.sa_flags & SA_RESTORER) +		restorer = ksig->ka.sa.sa_restorer;  	/* Set up to return from userspace.  */  	err |= __put_user(restorer, &frame->pretcode); @@ -331,7 +322,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,  	/* Set up registers for signal handler */  	regs->sp = (unsigned long)frame; -	regs->ip = (unsigned long)ka->sa.sa_handler; +	regs->ip = (unsigned long)ksig->ka.sa.sa_handler;  	regs->ax = (unsigned long)sig;  	regs->dx = 0;  	regs->cx = 0; @@ -344,7 +335,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,  	return 0;  } -static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +static int __setup_rt_frame(int sig, struct ksignal *ksig,  			    sigset_t *set, struct pt_regs *regs)  {  	struct rt_sigframe __user *frame; @@ -352,7 +343,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	int err = 0;  	void __user *fpstate = NULL; -	frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate); +	frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate);  	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))  		return -EFAULT; @@ -361,7 +352,6 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		put_user_ex(sig, &frame->sig);  		put_user_ex(&frame->info, &frame->pinfo);  		put_user_ex(&frame->uc, &frame->puc); -		err |= copy_siginfo_to_user(&frame->info, info);  		/* Create the ucontext.  */  		if (cpu_has_xsave) @@ -369,18 +359,13 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		else  			put_user_ex(0, &frame->uc.uc_flags);  		put_user_ex(0, &frame->uc.uc_link); -		put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); -		put_user_ex(sas_ss_flags(regs->sp), -			    &frame->uc.uc_stack.ss_flags); -		put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size); -		err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, -					regs, set->sig[0]); -		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); +		save_altstack_ex(&frame->uc.uc_stack, regs->sp);  		/* Set up to return from userspace.  */ -		restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); -		if (ka->sa.sa_flags & SA_RESTORER) -			restorer = ka->sa.sa_restorer; +		restorer = current->mm->context.vdso + +			selected_vdso32->sym___kernel_rt_sigreturn; +		if (ksig->ka.sa.sa_flags & SA_RESTORER) +			restorer = ksig->ka.sa.sa_restorer;  		put_user_ex(restorer, &frame->pretcode);  		/* @@ -392,13 +377,18 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		 */  		put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);  	} put_user_catch(err); +	 +	err |= copy_siginfo_to_user(&frame->info, &ksig->info); +	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, +				regs, set->sig[0]); +	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));  	if (err)  		return -EFAULT;  	/* Set up registers for signal handler */  	regs->sp = (unsigned long)frame; -	regs->ip = (unsigned long)ka->sa.sa_handler; +	regs->ip = (unsigned long)ksig->ka.sa.sa_handler;  	regs->ax = (unsigned long)sig;  	regs->dx = (unsigned long)&frame->info;  	regs->cx = (unsigned long)&frame->uc; @@ -411,21 +401,20 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	return 0;  }  #else /* !CONFIG_X86_32 */ -static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, +static int __setup_rt_frame(int sig, struct ksignal *ksig,  			    sigset_t *set, struct pt_regs *regs)  {  	struct rt_sigframe __user *frame;  	void __user *fp = NULL;  	int err = 0; -	struct task_struct *me = current; -	frame = get_sigframe(ka, regs, sizeof(struct rt_sigframe), &fp); +	frame = get_sigframe(&ksig->ka, regs, sizeof(struct rt_sigframe), &fp);  	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))  		return -EFAULT; -	if (ka->sa.sa_flags & SA_SIGINFO) { -		if (copy_siginfo_to_user(&frame->info, info)) +	if (ksig->ka.sa.sa_flags & SA_SIGINFO) { +		if (copy_siginfo_to_user(&frame->info, &ksig->info))  			return -EFAULT;  	} @@ -436,24 +425,22 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  		else  			put_user_ex(0, &frame->uc.uc_flags);  		put_user_ex(0, &frame->uc.uc_link); -		put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); -		put_user_ex(sas_ss_flags(regs->sp), -			    &frame->uc.uc_stack.ss_flags); -		put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size); -		err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); -		err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); +		save_altstack_ex(&frame->uc.uc_stack, regs->sp);  		/* Set up to return from userspace.  If provided, use a stub  		   already in userspace.  */  		/* x86-64 should always use SA_RESTORER. */ -		if (ka->sa.sa_flags & SA_RESTORER) { -			put_user_ex(ka->sa.sa_restorer, &frame->pretcode); +		if (ksig->ka.sa.sa_flags & SA_RESTORER) { +			put_user_ex(ksig->ka.sa.sa_restorer, &frame->pretcode);  		} else {  			/* could use a vstub here */  			err |= -EFAULT;  		}  	} put_user_catch(err); +	err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); +	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); +  	if (err)  		return -EFAULT; @@ -466,7 +453,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  	   next argument after the signal number on the stack. */  	regs->si = (unsigned long)&frame->info;  	regs->dx = (unsigned long)&frame->uc; -	regs->ip = (unsigned long) ka->sa.sa_handler; +	regs->ip = (unsigned long) ksig->ka.sa.sa_handler;  	regs->sp = (unsigned long)frame; @@ -478,86 +465,79 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,  }  #endif /* CONFIG_X86_32 */ -#ifdef CONFIG_X86_32 -/* - * Atomically swap in the new signal mask, and wait for a signal. - */ -asmlinkage int -sys_sigsuspend(int history0, int history1, old_sigset_t mask) +static int x32_setup_rt_frame(struct ksignal *ksig, +			      compat_sigset_t *set, +			      struct pt_regs *regs)  { -	mask &= _BLOCKABLE; -	spin_lock_irq(¤t->sighand->siglock); -	current->saved_sigmask = current->blocked; -	siginitset(¤t->blocked, mask); -	recalc_sigpending(); -	spin_unlock_irq(¤t->sighand->siglock); - -	current->state = TASK_INTERRUPTIBLE; -	schedule(); -	set_restore_sigmask(); - -	return -ERESTARTNOHAND; -} +#ifdef CONFIG_X86_X32_ABI +	struct rt_sigframe_x32 __user *frame; +	void __user *restorer; +	int err = 0; +	void __user *fpstate = NULL; -asmlinkage int -sys_sigaction(int sig, const struct old_sigaction __user *act, -	      struct old_sigaction __user *oact) -{ -	struct k_sigaction new_ka, old_ka; -	int ret = 0; +	frame = get_sigframe(&ksig->ka, regs, sizeof(*frame), &fpstate); -	if (act) { -		old_sigset_t mask; +	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) +		return -EFAULT; -		if (!access_ok(VERIFY_READ, act, sizeof(*act))) +	if (ksig->ka.sa.sa_flags & SA_SIGINFO) { +		if (copy_siginfo_to_user32(&frame->info, &ksig->info))  			return -EFAULT; +	} + +	put_user_try { +		/* Create the ucontext.  */ +		if (cpu_has_xsave) +			put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags); +		else +			put_user_ex(0, &frame->uc.uc_flags); +		put_user_ex(0, &frame->uc.uc_link); +		compat_save_altstack_ex(&frame->uc.uc_stack, regs->sp); +		put_user_ex(0, &frame->uc.uc__pad0); -		get_user_try { -			get_user_ex(new_ka.sa.sa_handler, &act->sa_handler); -			get_user_ex(new_ka.sa.sa_flags, &act->sa_flags); -			get_user_ex(mask, &act->sa_mask); -			get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer); -		} get_user_catch(ret); +		if (ksig->ka.sa.sa_flags & SA_RESTORER) { +			restorer = ksig->ka.sa.sa_restorer; +		} else { +			/* could use a vstub here */ +			restorer = NULL; +			err |= -EFAULT; +		} +		put_user_ex(restorer, &frame->pretcode); +	} put_user_catch(err); -		if (ret) -			return -EFAULT; -		siginitset(&new_ka.sa.sa_mask, mask); -	} +	err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate, +				regs, set->sig[0]); +	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); -	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); +	if (err) +		return -EFAULT; -	if (!ret && oact) { -		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) -			return -EFAULT; +	/* Set up registers for signal handler */ +	regs->sp = (unsigned long) frame; +	regs->ip = (unsigned long) ksig->ka.sa.sa_handler; -		put_user_try { -			put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler); -			put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags); -			put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); -			put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer); -		} put_user_catch(ret); +	/* We use the x32 calling convention here... */ +	regs->di = ksig->sig; +	regs->si = (unsigned long) &frame->info; +	regs->dx = (unsigned long) &frame->uc; -		if (ret) -			return -EFAULT; -	} +	loadsegment(ds, __USER_DS); +	loadsegment(es, __USER_DS); -	return ret; -} -#endif /* CONFIG_X86_32 */ +	regs->cs = __USER_CS; +	regs->ss = __USER_DS; +#endif	/* CONFIG_X86_X32_ABI */ -long -sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, -		struct pt_regs *regs) -{ -	return do_sigaltstack(uss, uoss, regs->sp); +	return 0;  }  /*   * Do a signal return; undo the signal stack.   */  #ifdef CONFIG_X86_32 -unsigned long sys_sigreturn(struct pt_regs *regs) +asmlinkage unsigned long sys_sigreturn(void)  { +	struct pt_regs *regs = current_pt_regs();  	struct sigframe __user *frame;  	unsigned long ax;  	sigset_t set; @@ -571,11 +551,7 @@ unsigned long sys_sigreturn(struct pt_regs *regs)  				    sizeof(frame->extramask))))  		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->sc, &ax))  		goto badframe; @@ -588,8 +564,9 @@ badframe:  }  #endif /* CONFIG_X86_32 */ -long sys_rt_sigreturn(struct pt_regs *regs) +asmlinkage long sys_rt_sigreturn(void)  { +	struct pt_regs *regs = current_pt_regs();  	struct rt_sigframe __user *frame;  	unsigned long ax;  	sigset_t set; @@ -600,16 +577,12 @@ long sys_rt_sigreturn(struct pt_regs *regs)  	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, &ax))  		goto badframe; -	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT) +	if (restore_altstack(&frame->uc.uc_stack))  		goto badframe;  	return ax; @@ -633,57 +606,30 @@ static int signr_convert(int sig)  	return sig;  } -#ifdef CONFIG_X86_32 - -#define is_ia32	1 -#define ia32_setup_frame	__setup_frame -#define ia32_setup_rt_frame	__setup_rt_frame - -#else /* !CONFIG_X86_32 */ - -#ifdef CONFIG_IA32_EMULATION -#define is_ia32	test_thread_flag(TIF_IA32) -#else /* !CONFIG_IA32_EMULATION */ -#define is_ia32	0 -#endif /* CONFIG_IA32_EMULATION */ - -int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, -		sigset_t *set, struct pt_regs *regs); -int ia32_setup_frame(int sig, struct k_sigaction *ka, -		sigset_t *set, struct pt_regs *regs); - -#endif /* CONFIG_X86_32 */ -  static int -setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, -	       sigset_t *set, struct pt_regs *regs) +setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs)  { -	int usig = signr_convert(sig); -	int ret; +	int usig = signr_convert(ksig->sig); +	sigset_t *set = sigmask_to_save(); +	compat_sigset_t *cset = (compat_sigset_t *) set;  	/* Set up the stack frame */ -	if (is_ia32) { -		if (ka->sa.sa_flags & SA_SIGINFO) -			ret = ia32_setup_rt_frame(usig, ka, info, set, regs); +	if (is_ia32_frame()) { +		if (ksig->ka.sa.sa_flags & SA_SIGINFO) +			return ia32_setup_rt_frame(usig, ksig, cset, regs);  		else -			ret = ia32_setup_frame(usig, ka, set, regs); -	} else -		ret = __setup_rt_frame(sig, ka, info, set, regs); - -	if (ret) { -		force_sigsegv(sig, current); -		return -EFAULT; +			return ia32_setup_frame(usig, ksig, cset, regs); +	} else if (is_x32_frame()) { +		return x32_setup_rt_frame(ksig, cset, regs); +	} else { +		return __setup_rt_frame(ksig->sig, ksig, set, regs);  	} - -	return ret;  } -static int -handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka, -	      sigset_t *oldset, struct pt_regs *regs) +static void +handle_signal(struct ksignal *ksig, struct pt_regs *regs)  { -	int ret; - +	bool failed;  	/* Are we from a system call? */  	if (syscall_get_nr(current, regs) >= 0) {  		/* If so, check system call restarting.. */ @@ -694,7 +640,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,  			break;  		case -ERESTARTSYS: -			if (!(ka->sa.sa_flags & SA_RESTART)) { +			if (!(ksig->ka.sa.sa_flags & SA_RESTART)) {  				regs->ax = -EINTR;  				break;  			} @@ -714,44 +660,23 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,  	    likely(test_and_clear_thread_flag(TIF_FORCED_TF)))  		regs->flags &= ~X86_EFLAGS_TF; -	ret = setup_rt_frame(sig, ka, info, oldset, regs); - -	if (ret) -		return ret; - -#ifdef CONFIG_X86_64 -	/* -	 * This has nothing to do with segment registers, -	 * despite the name.  This magic affects uaccess.h -	 * macros' behavior.  Reset it to the normal setting. -	 */ -	set_fs(USER_DS); -#endif - -	/* -	 * Clear the direction flag as per the ABI for function entry. -	 */ -	regs->flags &= ~X86_EFLAGS_DF; - -	/* -	 * Clear TF when entering the signal handler, but -	 * notify any tracer that was single-stepping it. -	 * The tracer may want to single-step inside the -	 * handler too. -	 */ -	regs->flags &= ~X86_EFLAGS_TF; - -	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); - -	tracehook_signal_handler(sig, info, ka, regs, -				 test_thread_flag(TIF_SINGLESTEP)); - -	return 0; +	failed = (setup_rt_frame(ksig, regs) < 0); +	if (!failed) { +		/* +		 * Clear the direction flag as per the ABI for function entry. +		 * +		 * Clear RF when entering the signal handler, because +		 * it might disable possible debug exception from the +		 * signal handler. +		 * +		 * Clear TF when entering the signal handler, but +		 * notify any tracer that was single-stepping it. +		 * The tracer may want to single-step inside the +		 * handler too. +		 */ +		regs->flags &= ~(X86_EFLAGS_DF|X86_EFLAGS_RF|X86_EFLAGS_TF); +	} +	signal_setup_done(failed, ksig, test_thread_flag(TIF_SINGLESTEP));  }  #ifdef CONFIG_X86_32 @@ -768,38 +693,11 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,   */  static void do_signal(struct pt_regs *regs)  { -	struct k_sigaction ka; -	siginfo_t info; -	int signr; -	sigset_t *oldset; - -	/* -	 * 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. -	 * X86_32: vm86 regs switched out by assembly code before reaching -	 * here, so testing against kernel CS suffices. -	 */ -	if (!user_mode(regs)) -		return; - -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) -		oldset = ¤t->saved_sigmask; -	else -		oldset = ¤t->blocked; +	struct ksignal ksig; -	signr = get_signal_to_deliver(&info, &ka, regs, NULL); -	if (signr > 0) { +	if (get_signal(&ksig)) {  		/* Whee! Actually deliver the signal.  */ -		if (handle_signal(signr, &info, &ka, 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 TS_RESTORE_SIGMASK flag. -			 */ -			current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		} +		handle_signal(&ksig, regs);  		return;  	} @@ -825,25 +723,27 @@ static void do_signal(struct pt_regs *regs)  	 * If there's no signal to deliver, we just put the saved sigmask  	 * back.  	 */ -	if (current_thread_info()->status & TS_RESTORE_SIGMASK) { -		current_thread_info()->status &= ~TS_RESTORE_SIGMASK; -		sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); -	} +	restore_saved_sigmask();  }  /*   * notification of userspace execution resumption   * - triggered by the TIF_WORK_MASK flags   */ -void +__visible void  do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)  { +	user_exit(); +  #ifdef CONFIG_X86_MCE  	/* notify userspace of pending MCEs */  	if (thread_info_flags & _TIF_MCE_NOTIFY)  		mce_notify_process();  #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ +	if (thread_info_flags & _TIF_UPROBE) +		uprobe_notify_resume(regs); +  	/* deal with pending signal delivery */  	if (thread_info_flags & _TIF_SIGPENDING)  		do_signal(regs); @@ -851,15 +751,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)  	if (thread_info_flags & _TIF_NOTIFY_RESUME) {  		clear_thread_flag(TIF_NOTIFY_RESUME);  		tracehook_notify_resume(regs); -		if (current->replacement_session_keyring) -			key_replace_session_keyring();  	}  	if (thread_info_flags & _TIF_USER_RETURN_NOTIFY)  		fire_user_return_notifiers(); -#ifdef CONFIG_X86_32 -	clear_thread_flag(TIF_IRET); -#endif /* CONFIG_X86_32 */ +	user_enter();  }  void signal_fault(struct pt_regs *regs, void __user *frame, char *where) @@ -873,8 +769,39 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)  		       me->comm, me->pid, where, frame,  		       regs->ip, regs->sp, regs->orig_ax);  		print_vma_addr(" in ", regs->ip); -		printk(KERN_CONT "\n"); +		pr_cont("\n");  	}  	force_sig(SIGSEGV, me);  } + +#ifdef CONFIG_X86_X32_ABI +asmlinkage long sys32_x32_rt_sigreturn(void) +{ +	struct pt_regs *regs = current_pt_regs(); +	struct rt_sigframe_x32 __user *frame; +	sigset_t set; +	unsigned long ax; + +	frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8); + +	if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) +		goto badframe; +	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) +		goto badframe; + +	set_current_blocked(&set); + +	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax)) +		goto badframe; + +	if (compat_restore_altstack(&frame->uc.uc_stack)) +		goto badframe; + +	return ax; + +badframe: +	signal_fault(regs, frame, "x32 rt_sigreturn"); +	return 0; +} +#endif  | 
