Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/signal

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()
  ...
  • Loading branch information
torvalds committed May 24, 2012
2 parents 05f144a + 415d04d commit f936991
Show file tree
Hide file tree
Showing 54 changed files with 386 additions and 817 deletions.
80 changes: 27 additions & 53 deletions arch/alpha/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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. */
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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);

Expand All @@ -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. */
Expand All @@ -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;
Expand All @@ -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)
block_sigmask(ka, sig);

return ret;
if (ret) {
force_sigsegv(sig, current);
return;
}
block_sigmask(ka, sig);
/* 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
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand All @@ -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 */
Expand All @@ -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) {
Expand Down
11 changes: 1 addition & 10 deletions arch/arm/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 0 additions & 7 deletions arch/avr32/include/asm/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
30 changes: 12 additions & 18 deletions arch/avr32/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

/*
Expand Down
21 changes: 5 additions & 16 deletions arch/blackfin/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
3 changes: 3 additions & 0 deletions arch/c6x/kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ asmlinkage int do_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;

/*
* Since we stacked the signal on a dword boundary,
* 'sp' should be dword aligned here. If it's
Expand Down
Loading

0 comments on commit f936991

Please sign in to comment.