Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84e9c95a authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'x86/signal' into core/signal

parents 206855c3 1389ac4b
Loading
Loading
Loading
Loading
+14 −17
Original line number Diff line number Diff line
@@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
	savesegment(es, tmp);
	err |= __put_user(tmp, (unsigned int __user *)&sc->es);

	err |= __put_user((u32)regs->di, &sc->di);
	err |= __put_user((u32)regs->si, &sc->si);
	err |= __put_user((u32)regs->bp, &sc->bp);
	err |= __put_user((u32)regs->sp, &sc->sp);
	err |= __put_user((u32)regs->bx, &sc->bx);
	err |= __put_user((u32)regs->dx, &sc->dx);
	err |= __put_user((u32)regs->cx, &sc->cx);
	err |= __put_user((u32)regs->ax, &sc->ax);
	err |= __put_user((u32)regs->cs, &sc->cs);
	err |= __put_user((u32)regs->ss, &sc->ss);
	err |= __put_user(regs->di, &sc->di);
	err |= __put_user(regs->si, &sc->si);
	err |= __put_user(regs->bp, &sc->bp);
	err |= __put_user(regs->sp, &sc->sp);
	err |= __put_user(regs->bx, &sc->bx);
	err |= __put_user(regs->dx, &sc->dx);
	err |= __put_user(regs->cx, &sc->cx);
	err |= __put_user(regs->ax, &sc->ax);
	err |= __put_user(regs->cs, &sc->cs);
	err |= __put_user(regs->ss, &sc->ss);
	err |= __put_user(current->thread.trap_no, &sc->trapno);
	err |= __put_user(current->thread.error_code, &sc->err);
	err |= __put_user((u32)regs->ip, &sc->ip);
	err |= __put_user((u32)regs->flags, &sc->flags);
	err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
	err |= __put_user(regs->ip, &sc->ip);
	err |= __put_user(regs->flags, &sc->flags);
	err |= __put_user(regs->sp, &sc->sp_at_signal);

	tmp = save_i387_xstate_ia32(fpstate);
	if (tmp < 0)
		err = -EFAULT;
	else {
		clear_used_math();
		stts();
	else
		err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
					&sc->fpstate);
	}

	/* non-iBCS2 extensions.. */
	err |= __put_user(mask, &sc->oldmask);
+66 −42
Original line number Diff line number Diff line
@@ -113,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx)
	return do_sigaltstack(uss, uoss, regs->sp);
}

#define COPY(x)			{		\
	err |= __get_user(regs->x, &sc->x);	\
}

#define COPY_SEG(seg)		{			\
		unsigned short tmp;			\
		err |= __get_user(tmp, &sc->seg);	\
		regs->seg = tmp;			\
}

#define COPY_SEG_STRICT(seg)	{			\
		unsigned short tmp;			\
		err |= __get_user(tmp, &sc->seg);	\
		regs->seg = tmp | 3;			\
}

#define GET_SEG(seg)		{			\
		unsigned short tmp;			\
		err |= __get_user(tmp, &sc->seg);	\
		loadsegment(seg, tmp);			\
}

/*
 * Do a signal return; undo the signal stack.
@@ -121,28 +142,13 @@ static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
		   unsigned long *pax)
{
	void __user *buf;
	unsigned int tmpflags;
	unsigned int err = 0;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

#define COPY(x)		err |= __get_user(regs->x, &sc->x)

#define COPY_SEG(seg)							\
	{ unsigned short tmp;						\
	  err |= __get_user(tmp, &sc->seg);				\
	  regs->seg = tmp; }

#define COPY_SEG_STRICT(seg)						\
	{ unsigned short tmp;						\
	  err |= __get_user(tmp, &sc->seg);				\
	  regs->seg = tmp|3; }

#define GET_SEG(seg)							\
	{ unsigned short tmp;						\
	  err |= __get_user(tmp, &sc->seg);				\
	  loadsegment(seg, tmp); }

	GET_SEG(gs);
	COPY_SEG(fs);
	COPY_SEG(es);
@@ -152,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
	COPY_SEG_STRICT(cs);
	COPY_SEG_STRICT(ss);

	{
		unsigned int tmpflags;

	err |= __get_user(tmpflags, &sc->flags);
		regs->flags = (regs->flags & ~FIX_EFLAGS) |
						(tmpflags & FIX_EFLAGS);
	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
	regs->orig_ax = -1;		/* disable syscall checks */
	}

	{
		void __user *buf;

	err |= __get_user(buf, &sc->fpstate);
	err |= restore_i387_xstate(buf);
	}

	err |= __get_user(*pax, &sc->ax);
	return err;
@@ -482,24 +479,34 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/*
 * OK, we're invoking a handler:
 */
static int signr_convert(int sig)
{
	struct thread_info *info = current_thread_info();

	if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
		return info->exec_domain->signal_invmap[sig];
	return sig;
}

#define is_ia32	1
#define ia32_setup_frame	__setup_frame
#define ia32_setup_rt_frame	__setup_rt_frame

static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	       sigset_t *set, struct pt_regs *regs)
{
	int usig = signr_convert(sig);
	int ret;
	int usig;

	usig = current_thread_info()->exec_domain
		&& current_thread_info()->exec_domain->signal_invmap
		&& sig < 32
		? current_thread_info()->exec_domain->signal_invmap[sig]
		: sig;

	/* Set up the stack frame */
	if (is_ia32) {
		if (ka->sa.sa_flags & SA_SIGINFO)
		ret = __setup_rt_frame(usig, ka, info, set, regs);
			ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
		else
		ret = __setup_frame(usig, ka, set, regs);
			ret = ia32_setup_frame(usig, ka, set, regs);
	} else
		ret = __setup_rt_frame(sig, ka, info, set, regs);

	if (ret) {
		force_sigsegv(sig, current);
@@ -550,6 +557,15 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
	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.
	 */
@@ -663,6 +679,12 @@ static void do_signal(struct pt_regs *regs)
void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
	/* notify userspace of pending MCEs */
	if (thread_info_flags & _TIF_MCE_NOTIFY)
		mce_notify_user();
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */

	/* deal with pending signal delivery */
	if (thread_info_flags & _TIF_SIGPENDING)
		do_signal(regs);
@@ -672,7 +694,9 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
		tracehook_notify_resume(regs);
	}

#ifdef CONFIG_X86_32
	clear_thread_flag(TIF_IRET);
#endif /* CONFIG_X86_32 */
}

void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+53 −31
Original line number Diff line number Diff line
@@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
	return do_sigaltstack(uss, uoss, regs->sp);
}

#define COPY(x)			{		\
	err |= __get_user(regs->x, &sc->x);	\
}

#define COPY_SEG_STRICT(seg)	{			\
		unsigned short tmp;			\
		err |= __get_user(tmp, &sc->seg);	\
		regs->seg = tmp | 3;			\
}

/*
 * Do a signal return; undo the signal stack.
 */
@@ -59,13 +69,13 @@ static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
		   unsigned long *pax)
{
	void __user *buf;
	unsigned int tmpflags;
	unsigned int err = 0;

	/* Always make any pending restarted system calls return -EINTR */
	current_thread_info()->restart_block.fn = do_no_restart_syscall;

#define COPY(x)		(err |= __get_user(regs->x, &sc->x))

	COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
	COPY(dx); COPY(cx); COPY(ip);
	COPY(r8);
@@ -80,25 +90,14 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
	/* Kernel saves and restores only the CS segment register on signals,
	 * which is the bare minimum needed to allow mixed 32/64-bit code.
	 * App's signal handler can save/restore other segments if needed. */
	{
		unsigned cs;
		err |= __get_user(cs, &sc->cs);
		regs->cs = cs | 3;	/* Force into user mode */
	}
	COPY_SEG_STRICT(cs);

	{
		unsigned int tmpflags;
	err |= __get_user(tmpflags, &sc->flags);
	regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
	regs->orig_ax = -1;		/* disable syscall checks */
	}

	{
		void __user *buf;

	err |= __get_user(buf, &sc->fpstate);
	err |= restore_i387_xstate(buf);
	}

	err |= __get_user(*pax, &sc->ax);
	return err;
@@ -281,20 +280,31 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/*
 * OK, we're invoking a handler
 */
static int signr_convert(int sig)
{
	return sig;
}

#ifdef CONFIG_IA32_EMULATION
#define is_ia32	test_thread_flag(TIF_IA32)
#else
#define is_ia32	0
#endif

static int
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	       sigset_t *set, struct pt_regs *regs)
{
	int usig = signr_convert(sig);
	int ret;

#ifdef CONFIG_IA32_EMULATION
	if (test_thread_flag(TIF_IA32)) {
	/* Set up the stack frame */
	if (is_ia32) {
		if (ka->sa.sa_flags & SA_SIGINFO)
			ret = ia32_setup_rt_frame(sig, ka, info, set, regs);
			ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
		else
			ret = ia32_setup_frame(sig, ka, set, regs);
			ret = ia32_setup_frame(usig, ka, set, regs);
	} else
#endif
		ret = __setup_rt_frame(sig, ka, info, set, regs);

	if (ret) {
@@ -346,12 +356,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
	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.
@@ -410,7 +422,8 @@ static void do_signal(struct pt_regs *regs)

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
		/* Re-enable any watchpoints before delivering the
		/*
		 * Re-enable any watchpoints before delivering the
		 * signal to user space. The processor register will
		 * have been cleared if the watchpoint triggered
		 * inside the kernel.
@@ -441,6 +454,7 @@ static void do_signal(struct pt_regs *regs)
			regs->ax = regs->orig_ax;
			regs->ip -= 2;
			break;

		case -ERESTART_RESTARTBLOCK:
			regs->ax = NR_restart_syscall;
			regs->ip -= 2;
@@ -458,14 +472,18 @@ static void do_signal(struct pt_regs *regs)
	}
}

void do_notify_resume(struct pt_regs *regs, void *unused,
		      __u32 thread_info_flags)
/*
 * notification of userspace execution resumption
 * - triggered by the TIF_WORK_MASK flags
 */
void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
#ifdef CONFIG_X86_MCE
#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
	/* notify userspace of pending MCEs */
	if (thread_info_flags & _TIF_MCE_NOTIFY)
		mce_notify_user();
#endif /* CONFIG_X86_MCE */
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */

	/* deal with pending signal delivery */
	if (thread_info_flags & _TIF_SIGPENDING)
@@ -475,6 +493,10 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
		clear_thread_flag(TIF_NOTIFY_RESUME);
		tracehook_notify_resume(regs);
	}

#ifdef CONFIG_X86_32
	clear_thread_flag(TIF_IRET);
#endif /* CONFIG_X86_32 */
}

void signal_fault(struct pt_regs *regs, void __user *frame, char *where)