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

Commit 63b12bdb authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull arch signal handling cleanup from Richard Weinberger:
 "This patch series moves all remaining archs to the get_signal(),
  signal_setup_done() and sigsp() functions.

  Currently these archs use open coded variants of the said functions.
  Further, unused parameters get removed from get_signal_to_deliver(),
  tracehook_signal_handler() and signal_delivered().

  At the end of the day we save around 500 lines of code."

* 'signal-cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/misc: (43 commits)
  powerpc: Use sigsp()
  openrisc: Use sigsp()
  mn10300: Use sigsp()
  mips: Use sigsp()
  microblaze: Use sigsp()
  metag: Use sigsp()
  m68k: Use sigsp()
  m32r: Use sigsp()
  hexagon: Use sigsp()
  frv: Use sigsp()
  cris: Use sigsp()
  c6x: Use sigsp()
  blackfin: Use sigsp()
  avr32: Use sigsp()
  arm64: Use sigsp()
  arc: Use sigsp()
  sas_ss_flags: Remove nested ternary if
  Rip out get_signal_to_deliver()
  Clean up signal_delivered()
  tracehook_signal_handler: Remove sig, info, ka and regs
  ...
parents ad1f5caf 059ade65
Loading
Loading
Loading
Loading
+17 −30
Original line number Diff line number Diff line
@@ -141,17 +141,13 @@ SYSCALL_DEFINE0(rt_sigreturn)
/*
 * Determine which stack to use..
 */
static inline void __user *get_sigframe(struct k_sigaction *ka,
static inline void __user *get_sigframe(struct ksignal *ksig,
					struct pt_regs *regs,
					unsigned long framesize)
{
	unsigned long sp = regs->sp;
	unsigned long sp = sigsp(regs->sp, ksig);
	void __user *frame;

	/* This is the X/Open sanctioned signal stack switching */
	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
		sp = current->sas_ss_sp + current->sas_ss_size;

	/* No matter what happens, 'sp' must be word
	 * aligned otherwise nasty things could happen
	 */
@@ -179,14 +175,13 @@ static inline int map_sig(int sig)
}

static int
setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
	       sigset_t *set, struct pt_regs *regs)
setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
{
	struct rt_sigframe __user *sf;
	unsigned int magic = 0;
	int err = 0;

	sf = get_sigframe(ka, regs, sizeof(struct rt_sigframe));
	sf = get_sigframe(ksig, regs, sizeof(struct rt_sigframe));
	if (!sf)
		return 1;

@@ -205,8 +200,8 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
	 *  #2: struct siginfo
	 *  #3: struct ucontext (completely populated)
	 */
	if (unlikely(ka->sa.sa_flags & SA_SIGINFO)) {
		err |= copy_siginfo_to_user(&sf->info, info);
	if (unlikely(ksig->ka.sa.sa_flags & SA_SIGINFO)) {
		err |= copy_siginfo_to_user(&sf->info, &ksig->info);
		err |= __put_user(0, &sf->uc.uc_flags);
		err |= __put_user(NULL, &sf->uc.uc_link);
		err |= __save_altstack(&sf->uc.uc_stack, regs->sp);
@@ -227,16 +222,16 @@ setup_rt_frame(int signo, struct k_sigaction *ka, siginfo_t *info,
		return err;

	/* #1 arg to the user Signal handler */
	regs->r0 = map_sig(signo);
	regs->r0 = map_sig(ksig->sig);

	/* setup PC of user space signal handler */
	regs->ret = (unsigned long)ka->sa.sa_handler;
	regs->ret = (unsigned long)ksig->ka.sa.sa_handler;

	/*
	 * handler returns using sigreturn stub provided already by userpsace
	 */
	BUG_ON(!(ka->sa.sa_flags & SA_RESTORER));
	regs->blink = (unsigned long)ka->sa.sa_restorer;
	BUG_ON(!(ksig->ka.sa.sa_flags & SA_RESTORER));
	regs->blink = (unsigned long)ksig->ka.sa.sa_restorer;

	/* User Stack for signal handler will be above the frame just carved */
	regs->sp = (unsigned long)sf;
@@ -298,38 +293,30 @@ static void arc_restart_syscall(struct k_sigaction *ka, struct pt_regs *regs)
 * OK, we're invoking a handler
 */
static void
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
	      struct pt_regs *regs)
handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
	sigset_t *oldset = sigmask_to_save();
	int ret;

	/* Set up the stack frame */
	ret = setup_rt_frame(sig, ka, info, oldset, regs);
	ret = setup_rt_frame(ksig, oldset, regs);

	if (ret)
		force_sigsegv(sig, current);
	else
		signal_delivered(sig, info, ka, regs, 0);
	signal_setup_done(ret, ksig, 0);
}

void do_signal(struct pt_regs *regs)
{
	struct k_sigaction ka;
	siginfo_t info;
	int signr;
	struct ksignal ksig;
	int restart_scall;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);

	restart_scall = in_syscall(regs) && syscall_restartable(regs);

	if (signr > 0) {
	if (get_signal(&ksig)) {
		if (restart_scall) {
			arc_restart_syscall(&ka, regs);
			arc_restart_syscall(&ksig.ka, regs);
			syscall_wont_restart(regs);	/* No more restarts */
		}
		handle_signal(signr, &ka, &info, regs);
		handle_signal(&ksig, regs);
		return;
	}

+5 −6
Original line number Diff line number Diff line
@@ -24,22 +24,21 @@

extern const compat_ulong_t aarch32_sigret_code[6];

int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
		       struct pt_regs *regs);
int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
			  struct pt_regs *regs);
int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
			  sigset_t *set, struct pt_regs *regs);

void compat_setup_restart_syscall(struct pt_regs *regs);
#else

static inline int compat_setup_frame(int usid, struct k_sigaction *ka,
static inline int compat_setup_frame(int usid, struct ksignal *ksig,
				     sigset_t *set, struct pt_regs *regs)
{
	return -ENOSYS;
}

static inline int compat_setup_rt_frame(int usig, struct k_sigaction *ka,
					siginfo_t *info, sigset_t *set,
static inline int compat_setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
					struct pt_regs *regs)
{
	return -ENOSYS;
+22 −36
Original line number Diff line number Diff line
@@ -209,19 +209,13 @@ static int setup_sigframe(struct rt_sigframe __user *sf,
	return err;
}

static struct rt_sigframe __user *get_sigframe(struct k_sigaction *ka,
static struct rt_sigframe __user *get_sigframe(struct ksignal *ksig,
					       struct pt_regs *regs)
{
	unsigned long sp, sp_top;
	struct rt_sigframe __user *frame;

	sp = sp_top = regs->sp;

	/*
	 * This is the X/Open sanctioned signal stack switching.
	 */
	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
		sp = sp_top = current->sas_ss_sp + current->sas_ss_size;
	sp = sp_top = sigsp(regs->sp, ksig);

	sp = (sp - sizeof(struct rt_sigframe)) & ~15;
	frame = (struct rt_sigframe __user *)sp;
@@ -253,13 +247,13 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
	regs->regs[30] = (unsigned long)sigtramp;
}

static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
			  sigset_t *set, struct pt_regs *regs)
static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
			  struct pt_regs *regs)
{
	struct rt_sigframe __user *frame;
	int err = 0;

	frame = get_sigframe(ka, regs);
	frame = get_sigframe(ksig, regs);
	if (!frame)
		return 1;

@@ -269,9 +263,9 @@ static int setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
	err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
	err |= setup_sigframe(frame, regs, set);
	if (err == 0) {
		setup_return(regs, ka, frame, usig);
		if (ka->sa.sa_flags & SA_SIGINFO) {
			err |= copy_siginfo_to_user(&frame->info, info);
		setup_return(regs, &ksig->ka, frame, usig);
		if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
			err |= copy_siginfo_to_user(&frame->info, &ksig->info);
			regs->regs[1] = (unsigned long)&frame->info;
			regs->regs[2] = (unsigned long)&frame->uc;
		}
@@ -291,13 +285,12 @@ static void setup_restart_syscall(struct pt_regs *regs)
/*
 * OK, we're invoking a handler
 */
static void handle_signal(unsigned long sig, struct k_sigaction *ka,
			  siginfo_t *info, struct pt_regs *regs)
static void handle_signal(struct ksignal *ksig, 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 usig = ksig->sig;
	int ret;

	/*
@@ -310,13 +303,12 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
	 * Set up the stack frame
	 */
	if (is_compat_task()) {
		if (ka->sa.sa_flags & SA_SIGINFO)
			ret = compat_setup_rt_frame(usig, ka, info, oldset,
						    regs);
		if (ksig->ka.sa.sa_flags & SA_SIGINFO)
			ret = compat_setup_rt_frame(usig, ksig, oldset, regs);
		else
			ret = compat_setup_frame(usig, ka, oldset, regs);
			ret = compat_setup_frame(usig, ksig, oldset, regs);
	} else {
		ret = setup_rt_frame(usig, ka, info, oldset, regs);
		ret = setup_rt_frame(usig, ksig, oldset, regs);
	}

	/*
@@ -324,18 +316,14 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
	 */
	ret |= !valid_user_regs(&regs->user_regs);

	if (ret != 0) {
		force_sigsegv(sig, tsk);
		return;
	}

	/*
	 * Fast forward the stepping logic so we step into the signal
	 * handler.
	 */
	if (!ret)
		user_fastforward_single_step(tsk);

	signal_delivered(sig, info, ka, regs, 0);
	signal_setup_done(ret, ksig, 0);
}

/*
@@ -350,10 +338,9 @@ static void handle_signal(unsigned long sig, struct k_sigaction *ka,
static void do_signal(struct pt_regs *regs)
{
	unsigned long continue_addr = 0, restart_addr = 0;
	struct k_sigaction ka;
	siginfo_t info;
	int signr, retval = 0;
	int retval = 0;
	int syscall = (int)regs->syscallno;
	struct ksignal ksig;

	/*
	 * If we were from a system call, check for system call restarting...
@@ -387,8 +374,7 @@ static void do_signal(struct pt_regs *regs)
	 * Get the signal to deliver. When running under ptrace, at this point
	 * the debugger may change all of our registers.
	 */
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
	if (get_signal(&ksig)) {
		/*
		 * Depending on the signal settings, we may need to revert the
		 * decision to restart the system call, but skip this if a
@@ -398,12 +384,12 @@ static void do_signal(struct pt_regs *regs)
		    (retval == -ERESTARTNOHAND ||
		     retval == -ERESTART_RESTARTBLOCK ||
		     (retval == -ERESTARTSYS &&
		      !(ka.sa.sa_flags & SA_RESTART)))) {
		      !(ksig.ka.sa.sa_flags & SA_RESTART)))) {
			regs->regs[0] = -EINTR;
			regs->pc = continue_addr;
		}

		handle_signal(signr, &ka, &info, regs);
		handle_signal(&ksig, regs);
		return;
	}

+9 −15
Original line number Diff line number Diff line
@@ -407,19 +407,13 @@ asmlinkage int compat_sys_rt_sigreturn(struct pt_regs *regs)
	return 0;
}

static void __user *compat_get_sigframe(struct k_sigaction *ka,
static void __user *compat_get_sigframe(struct ksignal *ksig,
					struct pt_regs *regs,
					int framesize)
{
	compat_ulong_t sp = regs->compat_sp;
	compat_ulong_t sp = sigsp(regs->compat_sp, ksig);
	void __user *frame;

	/*
	 * This is the X/Open sanctioned signal stack switching.
	 */
	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
		sp = current->sas_ss_sp + current->sas_ss_size;

	/*
	 * ATPCS B01 mandates 8-byte alignment
	 */
@@ -520,18 +514,18 @@ static int compat_setup_sigframe(struct compat_sigframe __user *sf,
/*
 * 32-bit signal handling routines called from signal.c
 */
int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
int compat_setup_rt_frame(int usig, struct ksignal *ksig,
			  sigset_t *set, struct pt_regs *regs)
{
	struct compat_rt_sigframe __user *frame;
	int err = 0;

	frame = compat_get_sigframe(ka, regs, sizeof(*frame));
	frame = compat_get_sigframe(ksig, regs, sizeof(*frame));

	if (!frame)
		return 1;

	err |= copy_siginfo_to_user32(&frame->info, info);
	err |= copy_siginfo_to_user32(&frame->info, &ksig->info);

	__put_user_error(0, &frame->sig.uc.uc_flags, err);
	__put_user_error(0, &frame->sig.uc.uc_link, err);
@@ -541,7 +535,7 @@ int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
	err |= compat_setup_sigframe(&frame->sig, regs, set);

	if (err == 0) {
		compat_setup_return(regs, ka, frame->sig.retcode, frame, usig);
		compat_setup_return(regs, &ksig->ka, frame->sig.retcode, frame, usig);
		regs->regs[1] = (compat_ulong_t)(unsigned long)&frame->info;
		regs->regs[2] = (compat_ulong_t)(unsigned long)&frame->sig.uc;
	}
@@ -549,13 +543,13 @@ int compat_setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info,
	return err;
}

int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,
int compat_setup_frame(int usig, struct ksignal *ksig, sigset_t *set,
		       struct pt_regs *regs)
{
	struct compat_sigframe __user *frame;
	int err = 0;

	frame = compat_get_sigframe(ka, regs, sizeof(*frame));
	frame = compat_get_sigframe(ksig, regs, sizeof(*frame));

	if (!frame)
		return 1;
@@ -564,7 +558,7 @@ int compat_setup_frame(int usig, struct k_sigaction *ka, sigset_t *set,

	err |= compat_setup_sigframe(frame, regs, set);
	if (err == 0)
		compat_setup_return(regs, ka, frame->retcode, frame, usig);
		compat_setup_return(regs, &ksig->ka, frame->retcode, frame, usig);

	return err;
}
+20 −30
Original line number Diff line number Diff line
@@ -127,24 +127,20 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
}

static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
get_sigframe(struct ksignal *ksig, struct pt_regs *regs, int framesize)
{
	unsigned long sp = regs->sp;

	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
		sp = current->sas_ss_sp + current->sas_ss_size;
	unsigned long sp = sigsp(regs->sp, ksig);

	return (void __user *)((sp - framesize) & ~3);
}

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, sigset_t *set, struct pt_regs *regs)
{
	struct rt_sigframe __user *frame;
	int err = 0;

	frame = get_sigframe(ka, regs, sizeof(*frame));
	frame = get_sigframe(ksig, regs, sizeof(*frame));
	err = -EFAULT;
	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
		goto out;
@@ -164,7 +160,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	err = __put_user(0x3008d733 | (__NR_rt_sigreturn << 20),
			 &frame->retcode);

	err |= copy_siginfo_to_user(&frame->info, info);
	err |= copy_siginfo_to_user(&frame->info, &ksig->info);

	/* Set up the ucontext */
	err |= __put_user(0, &frame->uc.uc_flags);
@@ -176,12 +172,12 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	if (err)
		goto out;

	regs->r12 = sig;
	regs->r12 = ksig->sig;
	regs->r11 = (unsigned long) &frame->info;
	regs->r10 = (unsigned long) &frame->uc;
	regs->sp = (unsigned long) frame;
	if (ka->sa.sa_flags & SA_RESTORER)
		regs->lr = (unsigned long)ka->sa.sa_restorer;
	if (ksig->ka.sa.sa_flags & SA_RESTORER)
		regs->lr = (unsigned long)ksig->ka.sa.sa_restorer;
	else {
		printk(KERN_NOTICE "[%s:%d] did not set SA_RESTORER\n",
		       current->comm, current->pid);
@@ -189,10 +185,10 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	}

	pr_debug("SIG deliver [%s:%d]: sig=%d sp=0x%lx pc=0x%lx->0x%p lr=0x%lx\n",
		 current->comm, current->pid, sig, regs->sp,
		 regs->pc, ka->sa.sa_handler, regs->lr);
		 current->comm, current->pid, ksig->sig, regs->sp,
		 regs->pc, ksig->ka.sa.sa_handler, regs->lr);

	regs->pc = (unsigned long) ka->sa.sa_handler;
	regs->pc = (unsigned long)ksig->ka.sa.sa_handler;

out:
	return err;
@@ -208,15 +204,14 @@ static inline void setup_syscall_restart(struct pt_regs *regs)
}

static inline void
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
	      struct pt_regs *regs, int syscall)
handle_signal(struct ksignal *ksig, struct pt_regs *regs, int syscall)
{
	int ret;

	/*
	 * Set up the stack frame
	 */
	ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs);
	ret = setup_rt_frame(ksig, sigmask_to_save(), regs);

	/*
	 * Check that the resulting registers are sane
@@ -226,10 +221,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
	/*
	 * Block the signal if we were successful.
	 */
	if (ret != 0)
		force_sigsegv(sig, current);
	else
		signal_delivered(sig, info, ka, regs, 0);
	signal_setup_done(ret, ksig, 0);
}

/*
@@ -239,9 +231,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
 */
static void do_signal(struct pt_regs *regs, int syscall)
{
	siginfo_t info;
	int signr;
	struct k_sigaction ka;
	struct ksignal ksig;

	/*
	 * We want the common case to go fast, which is why we may in
@@ -251,18 +241,18 @@ static void do_signal(struct pt_regs *regs, int syscall)
	if (!user_mode(regs))
		return;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	get_signal(&ksig);
	if (syscall) {
		switch (regs->r12) {
		case -ERESTART_RESTARTBLOCK:
		case -ERESTARTNOHAND:
			if (signr > 0) {
			if (ksig.sig > 0) {
				regs->r12 = -EINTR;
				break;
			}
			/* fall through */
		case -ERESTARTSYS:
			if (signr > 0 && !(ka.sa.sa_flags & SA_RESTART)) {
			if (ksig.sig > 0 && !(ksig.ka.sa.sa_flags & SA_RESTART)) {
				regs->r12 = -EINTR;
				break;
			}
@@ -272,13 +262,13 @@ static void do_signal(struct pt_regs *regs, int syscall)
		}
	}

	if (signr == 0) {
	if (!ksig.sig) {
		/* No signal to deliver -- put the saved sigmask back */
		restore_saved_sigmask();
		return;
	}

	handle_signal(signr, &ka, &info, regs, syscall);
	handle_signal(&ksig, regs, syscall);
}

asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti)
Loading