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

Commit f9369910 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull first series of signal handling cleanups from Al Viro:
 "This is just the first part of the queue (about a half of it);
  assorted fixes all over the place in signal handling.

  This one ends with all sigsuspend() implementations switched to
  generic one (->saved_sigmask-based).

  With this, a bunch of assorted old buglets are fixed and most of the
  missing bits of NOTIFY_RESUME hookup are in place.  Two more fixes sit
  in arm and um trees respectively, and there's a couple of broken ones
  that need obvious fixes - parisc and avr32 check TIF_NOTIFY_RESUME
  only on one of two codepaths; fixes for that will happen in the next
  series"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/signal: (55 commits)
  unicore32: if there's no handler we need to restore sigmask, syscall or no syscall
  xtensa: add handling of TIF_NOTIFY_RESUME
  microblaze: drop 'oldset' argument of do_notify_resume()
  microblaze: handle TIF_NOTIFY_RESUME
  score: add handling of NOTIFY_RESUME to do_notify_resume()
  m68k: add TIF_NOTIFY_RESUME and handle it.
  sparc: kill ancient comment in sparc_sigaction()
  h8300: missing checks of __get_user()/__put_user() return values
  frv: missing checks of __get_user()/__put_user() return values
  cris: missing checks of __get_user()/__put_user() return values
  powerpc: missing checks of __get_user()/__put_user() return values
  sh: missing checks of __get_user()/__put_user() return values
  sparc: missing checks of __get_user()/__put_user() return values
  avr32: struct old_sigaction is never used
  m32r: struct old_sigaction is never used
  xtensa: xtensa_sigaction doesn't exist
  alpha: tidy signal delivery up
  score: don't open-code force_sigsegv()
  cris: don't open-code force_sigsegv()
  blackfin: don't open-code force_sigsegv()
  ...
parents 05f144a0 415d04d0
Loading
Loading
Loading
Loading
+27 −53
Original line number Diff line number Diff line
@@ -34,9 +34,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))

asmlinkage void ret_from_sys_call(void);
static void do_signal(struct pt_regs *, struct switch_stack *,
		      unsigned long, unsigned long);


/*
 * The OSF/1 sigprocmask calling sequence is different from the
@@ -121,17 +118,8 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
SYSCALL_DEFINE1(sigsuspend, 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_thread_flag(TIF_RESTORE_SIGMASK);
	return -ERESTARTNOHAND;
	return sigsuspend(&blocked);
}

asmlinkage int
@@ -376,11 +364,11 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
	oldsp = rdusp();
	frame = get_sigframe(ka, oldsp, sizeof(*frame));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
		goto give_sigsegv;
		return -EFAULT;

	err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
	if (err)
		goto give_sigsegv;
		return -EFAULT;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
@@ -396,7 +384,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,

	/* Check that everything was written properly.  */
	if (err)
		goto give_sigsegv;
		return err;

	/* "Return" to the handler */
	regs->r26 = r26;
@@ -410,12 +398,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
	printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
		current->comm, current->pid, frame, regs->pc, regs->r26);
#endif

	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}

static int
@@ -428,7 +411,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	oldsp = rdusp();
	frame = get_sigframe(ka, oldsp, sizeof(*frame));
	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
		goto give_sigsegv;
		return -EFAULT;

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

@@ -443,7 +426,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
				set->sig[0], oldsp);
	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
	if (err)
		goto give_sigsegv;
		return -EFAULT;

	/* Set up to return from userspace.  If provided, use a stub
	   already in userspace.  */
@@ -459,7 +442,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
	}

	if (err)
		goto give_sigsegv;
		return -EFAULT;

	/* "Return" to the handler */
	regs->r26 = r26;
@@ -475,31 +458,37 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#endif

	return 0;

give_sigsegv:
	force_sigsegv(sig, current);
	return -EFAULT;
}


/*
 * OK, we're invoking a handler.
 */
static inline int
static inline void
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
	      sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
	      struct pt_regs * regs, struct switch_stack *sw)
{
	sigset_t *oldset = &current->blocked;
	int ret;

	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;

	if (ka->sa.sa_flags & SA_SIGINFO)
		ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
	else
		ret = setup_frame(sig, ka, oldset, regs, sw);

	if (ret == 0)
	if (ret) {
		force_sigsegv(sig, current);
		return;
	}
	block_sigmask(ka, sig);

	return ret;
	/* A signal was successfully delivered, and the
	   saved sigmask was stored on the signal frame,
	   and will be restored by sigreturn.  So we can
	   simply clear the restore sigmask flag.  */
	clear_thread_flag(TIF_RESTORE_SIGMASK);
}

static inline void
@@ -547,12 +536,6 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
	int signr;
	unsigned long single_stepping = ptrace_cancel_bpt(current);
	struct k_sigaction ka;
	sigset_t *oldset;

	if (test_thread_flag(TIF_RESTORE_SIGMASK))
		oldset = &current->saved_sigmask;
	else
		oldset = &current->blocked;

	/* This lets the debugger run, ... */
	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -564,14 +547,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
		/* Whee!  Actually deliver the signal.  */
		if (r0)
			syscall_restart(r0, r19, regs, &ka);
		if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
			/* A signal was successfully delivered, and the
			   saved sigmask was stored on the signal frame,
			   and will be restored by sigreturn.  So we can
			   simply clear the restore sigmask flag.  */
			if (test_thread_flag(TIF_RESTORE_SIGMASK))
				clear_thread_flag(TIF_RESTORE_SIGMASK);
		}
		handle_signal(signr, &ka, &info, regs, sw);
		if (single_stepping) 
			ptrace_set_bpt(current); /* re-set bpt */
		return;
@@ -596,10 +572,8 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
	}

	/* If there's no signal to deliver, we just restore the saved mask.  */
	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
		clear_thread_flag(TIF_RESTORE_SIGMASK);
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
	}
	if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
		set_current_blocked(&current->saved_sigmask);

	if (single_stepping)
		ptrace_set_bpt(current);	/* re-set breakpoint */
@@ -610,7 +584,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
		 unsigned long thread_info_flags,
		 unsigned long r0, unsigned long r19)
{
	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
	if (thread_info_flags & _TIF_SIGPENDING)
		do_signal(regs, sw, r0, r19);

	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+1 −10
Original line number Diff line number Diff line
@@ -67,17 +67,8 @@ const unsigned long syscall_restart_code[2] = {
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 
+0 −7
Original line number Diff line number Diff line
@@ -115,13 +115,6 @@ typedef unsigned long sigset_t;
#include <asm-generic/signal-defs.h>

#ifdef __KERNEL__
struct old_sigaction {
	__sighandler_t sa_handler;
	old_sigset_t sa_mask;
	unsigned long sa_flags;
	__sigrestore_t sa_restorer;
};

struct sigaction {
	__sighandler_t sa_handler;
	unsigned long sa_flags;
+12 −18
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
	struct rt_sigframe __user *frame;
	sigset_t set;

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

	frame = (struct rt_sigframe __user *)regs->sp;
	pr_debug("SIG return: frame = %p\n", frame);

@@ -87,10 +90,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
		goto badframe;

	sigdelsetmask(&set, ~_BLOCKABLE);
	spin_lock_irq(&current->sighand->siglock);
	current->blocked = set;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
	set_current_blocked(&set);

	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
		goto badframe;
@@ -238,22 +238,16 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
	 */
	ret |= !valid_user_regs(regs);

	/*
	 * Block the signal if we were unsuccessful.
	 */
	if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
		spin_lock_irq(&current->sighand->siglock);
		sigorsets(&current->blocked, &current->blocked,
			  &ka->sa.sa_mask);
		sigaddset(&current->blocked, sig);
		recalc_sigpending();
		spin_unlock_irq(&current->sighand->siglock);
	}

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

	force_sigsegv(sig, current);
	/*
	 * Block the signal if we were successful.
	 */
	block_sigmask(ka, sig);
	clear_thread_flag(TIF_RESTORE_SIGMASK);
}

/*
+5 −16
Original line number Diff line number Diff line
@@ -99,10 +99,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
		goto badframe;

	sigdelsetmask(&set, ~_BLOCKABLE);
	spin_lock_irq(&current->sighand->siglock);
	current->blocked = set;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);
	set_current_blocked(&set);

	if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
		goto badframe;
@@ -213,9 +210,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
	return 0;

 give_sigsegv:
	if (sig == SIGSEGV)
		ka->sa.sa_handler = SIG_DFL;
	force_sig(SIGSEGV, current);
	force_sigsegv(sig, current);
	return -EFAULT;
}

@@ -266,15 +261,9 @@ handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
	/* set up the stack frame */
	ret = setup_rt_frame(sig, ka, info, oldset, regs);

	if (ret == 0) {
		spin_lock_irq(&current->sighand->siglock);
		sigorsets(&current->blocked, &current->blocked,
			  &ka->sa.sa_mask);
		if (!(ka->sa.sa_flags & SA_NODEFER))
			sigaddset(&current->blocked, sig);
		recalc_sigpending();
		spin_unlock_irq(&current->sighand->siglock);
	}
	if (ret == 0)
		block_sigmask(ka, sig);

	return ret;
}

Loading