static int check_kill_permission(int sig, struct siginfo *info,
struct task_struct *t)
{
+ struct pid *sid;
int error;
if (!valid_signal(sig))
if (error)
return error;
- if (((sig != SIGCONT) || (task_session_nr(current) != task_session_nr(t)))
- && (current->euid ^ t->suid) && (current->euid ^ t->uid)
- && (current->uid ^ t->suid) && (current->uid ^ t->uid)
- && !capable(CAP_KILL))
- return -EPERM;
+ if ((current->euid ^ t->suid) && (current->euid ^ t->uid) &&
+ (current->uid ^ t->suid) && (current->uid ^ t->uid) &&
+ !capable(CAP_KILL)) {
+ switch (sig) {
+ case SIGCONT:
+ sid = task_session(t);
+ /*
+ * We don't return the error if sid == NULL. The
+ * task was unhashed, the caller must notice this.
+ */
+ if (!sid || sid == task_session(current))
+ break;
+ default:
+ return -EPERM;
+ }
+ }
return security_task_kill(t, info, sig, 0);
}
static void do_notify_parent_cldstop(struct task_struct *tsk, int why);
/*
- * Handle magic process-wide effects of stop/continue signals.
- * Unlike the signal actions, these happen immediately at signal-generation
+ * Handle magic process-wide effects of stop/continue signals. Unlike
+ * the signal actions, these happen immediately at signal-generation
* time regardless of blocking, ignoring, or handling. This does the
* actual continuing for SIGCONT, but not the actual stopping for stop
- * signals. The process stop is done as a signal action for SIG_DFL.
+ * signals. The process stop is done as a signal action for SIG_DFL.
+ *
+ * Returns true if the signal should be actually delivered, otherwise
+ * it should be dropped.
*/
-static void handle_stop_signal(int sig, struct task_struct *p)
+static int prepare_signal(int sig, struct task_struct *p)
{
struct signal_struct *signal = p->signal;
struct task_struct *t;
- if (signal->flags & SIGNAL_GROUP_EXIT)
+ if (unlikely(signal->flags & SIGNAL_GROUP_EXIT)) {
/*
- * The process is in the middle of dying already.
+ * The process is in the middle of dying, nothing to do.
*/
- return;
-
- if (sig_kernel_stop(sig)) {
+ } else if (sig_kernel_stop(sig)) {
/*
* This is a stop signal. Remove SIGCONT from all queues.
*/
why |= SIGNAL_CLD_STOPPED;
if (why) {
+ /*
+ * The first thread which returns from finish_stop()
+ * will take ->siglock, notice SIGNAL_CLD_MASK, and
+ * notify its parent. See get_signal_to_deliver().
+ */
signal->flags = why | SIGNAL_STOP_CONTINUED;
signal->group_stop_count = 0;
signal->group_exit_code = 0;
*/
signal->flags &= ~SIGNAL_STOP_DEQUEUED;
}
- } else if (sig == SIGKILL) {
- /*
- * Make sure that any pending stop signal already dequeued
- * is undone by the wakeup for SIGKILL.
- */
- signal->flags &= ~SIGNAL_STOP_DEQUEUED;
}
+
+ return !sig_ignored(p, sig);
}
/*
struct sigqueue *q;
assert_spin_locked(&t->sighand->siglock);
- handle_stop_signal(sig, t);
+ if (!prepare_signal(sig, t))
+ return 0;
pending = group ? &t->signal->shared_pending : &t->pending;
/*
* exactly one non-rt signal, so that we can get more
* detailed information about the cause of the signal.
*/
- if (sig_ignored(t, sig) || legacy_queue(pending, sig))
+ if (legacy_queue(pending, sig))
return 0;
-
- /*
- * Deliver the signal to listening signalfds. This must be called
- * with the sighand lock held.
- */
- signalfd_notify(t, sig);
-
/*
* fast-pathed signals for kernel-internal things like SIGSTOP
* or SIGKILL.
}
out_set:
+ signalfd_notify(t, sig);
sigaddset(&pending->signal, sig);
complete_signal(sig, t, group);
return 0;
__sigqueue_free(q);
}
-static int do_send_sigqueue(struct sigqueue *q, struct task_struct *t,
- int group)
+int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
{
int sig = q->info.si_signo;
struct sigpending *pending;
if (!likely(lock_task_sighand(t, &flags)))
goto ret;
- handle_stop_signal(sig, t);
-
- ret = 1;
- if (sig_ignored(t, sig))
+ ret = 1; /* the signal is ignored */
+ if (!prepare_signal(sig, t))
goto out;
ret = 0;
* If an SI_TIMER entry is already queue just increment
* the overrun count.
*/
-
BUG_ON(q->info.si_code != SI_TIMER);
q->info.si_overrun++;
goto out;
return ret;
}
-int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
-{
- return do_send_sigqueue(q, p, 0);
-}
-
-int
-send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
-{
- return do_send_sigqueue(q, p, 1);
-}
-
/*
* Wake up any threads in the parent blocked in wait* syscalls.
*/
try_to_freeze();
spin_lock_irq(&sighand->siglock);
-
+ /*
+ * Every stopped thread goes here after wakeup. Check to see if
+ * we should notify the parent, prepare_signal(SIGCONT) encodes
+ * the CLD_ si_code into SIGNAL_CLD_MASK bits.
+ */
if (unlikely(signal->flags & SIGNAL_CLD_MASK)) {
int why = (signal->flags & SIGNAL_STOP_CONTINUED)
? CLD_CONTINUED : CLD_STOPPED;
* Anything else is fatal, maybe with a core dump.
*/
current->flags |= PF_SIGNALED;
- if ((signr != SIGKILL) && print_fatal_signals)
- print_fatal_signal(regs, signr);
+
if (sig_kernel_coredump(signr)) {
+ if (print_fatal_signals)
+ print_fatal_signal(regs, signr);
/*
* If it was able to dump core, this kills all
* other threads in the group and synchronizes with