diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 49 |
1 files changed, 23 insertions, 26 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index b27c01a66448..792952381092 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -378,8 +378,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) | |||
378 | /* We only dequeue private signals from ourselves, we don't let | 378 | /* We only dequeue private signals from ourselves, we don't let |
379 | * signalfd steal them | 379 | * signalfd steal them |
380 | */ | 380 | */ |
381 | if (tsk == current) | 381 | signr = __dequeue_signal(&tsk->pending, mask, info); |
382 | signr = __dequeue_signal(&tsk->pending, mask, info); | ||
383 | if (!signr) { | 382 | if (!signr) { |
384 | signr = __dequeue_signal(&tsk->signal->shared_pending, | 383 | signr = __dequeue_signal(&tsk->signal->shared_pending, |
385 | mask, info); | 384 | mask, info); |
@@ -407,8 +406,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) | |||
407 | } | 406 | } |
408 | } | 407 | } |
409 | } | 408 | } |
410 | if (likely(tsk == current)) | 409 | recalc_sigpending(); |
411 | recalc_sigpending(); | ||
412 | if (signr && unlikely(sig_kernel_stop(signr))) { | 410 | if (signr && unlikely(sig_kernel_stop(signr))) { |
413 | /* | 411 | /* |
414 | * Set a marker that we have dequeued a stop signal. Our | 412 | * Set a marker that we have dequeued a stop signal. Our |
@@ -425,7 +423,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) | |||
425 | if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) | 423 | if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) |
426 | tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; | 424 | tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; |
427 | } | 425 | } |
428 | if ( signr && | 426 | if (signr && |
429 | ((info->si_code & __SI_MASK) == __SI_TIMER) && | 427 | ((info->si_code & __SI_MASK) == __SI_TIMER) && |
430 | info->si_sys_private){ | 428 | info->si_sys_private){ |
431 | /* | 429 | /* |
@@ -533,18 +531,18 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
533 | if (!valid_signal(sig)) | 531 | if (!valid_signal(sig)) |
534 | return error; | 532 | return error; |
535 | 533 | ||
536 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ | 534 | if (info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) { |
537 | if (error) | 535 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ |
538 | return error; | 536 | if (error) |
539 | 537 | return error; | |
540 | error = -EPERM; | 538 | error = -EPERM; |
541 | if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) | 539 | if (((sig != SIGCONT) || |
542 | && ((sig != SIGCONT) || | 540 | (process_session(current) != process_session(t))) |
543 | (process_session(current) != process_session(t))) | 541 | && (current->euid ^ t->suid) && (current->euid ^ t->uid) |
544 | && (current->euid ^ t->suid) && (current->euid ^ t->uid) | 542 | && (current->uid ^ t->suid) && (current->uid ^ t->uid) |
545 | && (current->uid ^ t->suid) && (current->uid ^ t->uid) | 543 | && !capable(CAP_KILL)) |
546 | && !capable(CAP_KILL)) | ||
547 | return error; | 544 | return error; |
545 | } | ||
548 | 546 | ||
549 | return security_task_kill(t, info, sig, 0); | 547 | return security_task_kill(t, info, sig, 0); |
550 | } | 548 | } |
@@ -1300,20 +1298,19 @@ struct sigqueue *sigqueue_alloc(void) | |||
1300 | void sigqueue_free(struct sigqueue *q) | 1298 | void sigqueue_free(struct sigqueue *q) |
1301 | { | 1299 | { |
1302 | unsigned long flags; | 1300 | unsigned long flags; |
1301 | spinlock_t *lock = ¤t->sighand->siglock; | ||
1302 | |||
1303 | BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); | 1303 | BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); |
1304 | /* | 1304 | /* |
1305 | * If the signal is still pending remove it from the | 1305 | * If the signal is still pending remove it from the |
1306 | * pending queue. | 1306 | * pending queue. We must hold ->siglock while testing |
1307 | * q->list to serialize with collect_signal(). | ||
1307 | */ | 1308 | */ |
1308 | if (unlikely(!list_empty(&q->list))) { | 1309 | spin_lock_irqsave(lock, flags); |
1309 | spinlock_t *lock = ¤t->sighand->siglock; | 1310 | if (!list_empty(&q->list)) |
1310 | read_lock(&tasklist_lock); | 1311 | list_del_init(&q->list); |
1311 | spin_lock_irqsave(lock, flags); | 1312 | spin_unlock_irqrestore(lock, flags); |
1312 | if (!list_empty(&q->list)) | 1313 | |
1313 | list_del_init(&q->list); | ||
1314 | spin_unlock_irqrestore(lock, flags); | ||
1315 | read_unlock(&tasklist_lock); | ||
1316 | } | ||
1317 | q->flags &= ~SIGQUEUE_PREALLOC; | 1314 | q->flags &= ~SIGQUEUE_PREALLOC; |
1318 | __sigqueue_free(q); | 1315 | __sigqueue_free(q); |
1319 | } | 1316 | } |