diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 79 |
1 files changed, 59 insertions, 20 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 1b3c921737e2..fb5da6d19f14 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | * to allow signals to be sent reliably. | 10 | * to allow signals to be sent reliably. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/config.h> | ||
| 14 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 16 | #include <linux/smp_lock.h> | 15 | #include <linux/smp_lock.h> |
| @@ -418,9 +417,8 @@ static int collect_signal(int sig, struct sigpending *list, siginfo_t *info) | |||
| 418 | static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, | 417 | static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, |
| 419 | siginfo_t *info) | 418 | siginfo_t *info) |
| 420 | { | 419 | { |
| 421 | int sig = 0; | 420 | int sig = next_signal(pending, mask); |
| 422 | 421 | ||
| 423 | sig = next_signal(pending, mask); | ||
| 424 | if (sig) { | 422 | if (sig) { |
| 425 | if (current->notifier) { | 423 | if (current->notifier) { |
| 426 | if (sigismember(current->notifier_mask, sig)) { | 424 | if (sigismember(current->notifier_mask, sig)) { |
| @@ -433,9 +431,7 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, | |||
| 433 | 431 | ||
| 434 | if (!collect_signal(sig, pending, info)) | 432 | if (!collect_signal(sig, pending, info)) |
| 435 | sig = 0; | 433 | sig = 0; |
| 436 | |||
| 437 | } | 434 | } |
| 438 | recalc_sigpending(); | ||
| 439 | 435 | ||
| 440 | return sig; | 436 | return sig; |
| 441 | } | 437 | } |
| @@ -452,6 +448,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) | |||
| 452 | if (!signr) | 448 | if (!signr) |
| 453 | signr = __dequeue_signal(&tsk->signal->shared_pending, | 449 | signr = __dequeue_signal(&tsk->signal->shared_pending, |
| 454 | mask, info); | 450 | mask, info); |
| 451 | recalc_sigpending_tsk(tsk); | ||
| 455 | if (signr && unlikely(sig_kernel_stop(signr))) { | 452 | if (signr && unlikely(sig_kernel_stop(signr))) { |
| 456 | /* | 453 | /* |
| 457 | * Set a marker that we have dequeued a stop signal. Our | 454 | * Set a marker that we have dequeued a stop signal. Our |
| @@ -584,7 +581,7 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
| 584 | && !capable(CAP_KILL)) | 581 | && !capable(CAP_KILL)) |
| 585 | return error; | 582 | return error; |
| 586 | 583 | ||
| 587 | error = security_task_kill(t, info, sig); | 584 | error = security_task_kill(t, info, sig, 0); |
| 588 | if (!error) | 585 | if (!error) |
| 589 | audit_signal_info(sig, t); /* Let audit system see the signal */ | 586 | audit_signal_info(sig, t); /* Let audit system see the signal */ |
| 590 | return error; | 587 | return error; |
| @@ -792,22 +789,31 @@ out: | |||
| 792 | /* | 789 | /* |
| 793 | * Force a signal that the process can't ignore: if necessary | 790 | * Force a signal that the process can't ignore: if necessary |
| 794 | * we unblock the signal and change any SIG_IGN to SIG_DFL. | 791 | * we unblock the signal and change any SIG_IGN to SIG_DFL. |
| 792 | * | ||
| 793 | * Note: If we unblock the signal, we always reset it to SIG_DFL, | ||
| 794 | * since we do not want to have a signal handler that was blocked | ||
| 795 | * be invoked when user space had explicitly blocked it. | ||
| 796 | * | ||
| 797 | * We don't want to have recursive SIGSEGV's etc, for example. | ||
| 795 | */ | 798 | */ |
| 796 | |||
| 797 | int | 799 | int |
| 798 | force_sig_info(int sig, struct siginfo *info, struct task_struct *t) | 800 | force_sig_info(int sig, struct siginfo *info, struct task_struct *t) |
| 799 | { | 801 | { |
| 800 | unsigned long int flags; | 802 | unsigned long int flags; |
| 801 | int ret; | 803 | int ret, blocked, ignored; |
| 804 | struct k_sigaction *action; | ||
| 802 | 805 | ||
| 803 | spin_lock_irqsave(&t->sighand->siglock, flags); | 806 | spin_lock_irqsave(&t->sighand->siglock, flags); |
| 804 | if (t->sighand->action[sig-1].sa.sa_handler == SIG_IGN) { | 807 | action = &t->sighand->action[sig-1]; |
| 805 | t->sighand->action[sig-1].sa.sa_handler = SIG_DFL; | 808 | ignored = action->sa.sa_handler == SIG_IGN; |
| 806 | } | 809 | blocked = sigismember(&t->blocked, sig); |
| 807 | if (sigismember(&t->blocked, sig)) { | 810 | if (blocked || ignored) { |
| 808 | sigdelset(&t->blocked, sig); | 811 | action->sa.sa_handler = SIG_DFL; |
| 812 | if (blocked) { | ||
| 813 | sigdelset(&t->blocked, sig); | ||
| 814 | recalc_sigpending_tsk(t); | ||
| 815 | } | ||
| 809 | } | 816 | } |
| 810 | recalc_sigpending_tsk(t); | ||
| 811 | ret = specific_send_sig_info(sig, info, t); | 817 | ret = specific_send_sig_info(sig, info, t); |
| 812 | spin_unlock_irqrestore(&t->sighand->siglock, flags); | 818 | spin_unlock_irqrestore(&t->sighand->siglock, flags); |
| 813 | 819 | ||
| @@ -1107,7 +1113,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
| 1107 | 1113 | ||
| 1108 | /* like kill_proc_info(), but doesn't use uid/euid of "current" */ | 1114 | /* like kill_proc_info(), but doesn't use uid/euid of "current" */ |
| 1109 | int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | 1115 | int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, |
| 1110 | uid_t uid, uid_t euid) | 1116 | uid_t uid, uid_t euid, u32 secid) |
| 1111 | { | 1117 | { |
| 1112 | int ret = -EINVAL; | 1118 | int ret = -EINVAL; |
| 1113 | struct task_struct *p; | 1119 | struct task_struct *p; |
| @@ -1127,6 +1133,9 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | |||
| 1127 | ret = -EPERM; | 1133 | ret = -EPERM; |
| 1128 | goto out_unlock; | 1134 | goto out_unlock; |
| 1129 | } | 1135 | } |
| 1136 | ret = security_task_kill(p, info, sig, secid); | ||
| 1137 | if (ret) | ||
| 1138 | goto out_unlock; | ||
| 1130 | if (sig && p->sighand) { | 1139 | if (sig && p->sighand) { |
| 1131 | unsigned long flags; | 1140 | unsigned long flags; |
| 1132 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1141 | spin_lock_irqsave(&p->sighand->siglock, flags); |
| @@ -1531,6 +1540,35 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why) | |||
| 1531 | spin_unlock_irqrestore(&sighand->siglock, flags); | 1540 | spin_unlock_irqrestore(&sighand->siglock, flags); |
| 1532 | } | 1541 | } |
| 1533 | 1542 | ||
| 1543 | static inline int may_ptrace_stop(void) | ||
| 1544 | { | ||
| 1545 | if (!likely(current->ptrace & PT_PTRACED)) | ||
| 1546 | return 0; | ||
| 1547 | |||
| 1548 | if (unlikely(current->parent == current->real_parent && | ||
| 1549 | (current->ptrace & PT_ATTACHED))) | ||
| 1550 | return 0; | ||
| 1551 | |||
| 1552 | if (unlikely(current->signal == current->parent->signal) && | ||
| 1553 | unlikely(current->signal->flags & SIGNAL_GROUP_EXIT)) | ||
| 1554 | return 0; | ||
| 1555 | |||
| 1556 | /* | ||
| 1557 | * Are we in the middle of do_coredump? | ||
| 1558 | * If so and our tracer is also part of the coredump stopping | ||
| 1559 | * is a deadlock situation, and pointless because our tracer | ||
| 1560 | * is dead so don't allow us to stop. | ||
| 1561 | * If SIGKILL was already sent before the caller unlocked | ||
| 1562 | * ->siglock we must see ->core_waiters != 0. Otherwise it | ||
| 1563 | * is safe to enter schedule(). | ||
| 1564 | */ | ||
| 1565 | if (unlikely(current->mm->core_waiters) && | ||
| 1566 | unlikely(current->mm == current->parent->mm)) | ||
| 1567 | return 0; | ||
| 1568 | |||
| 1569 | return 1; | ||
| 1570 | } | ||
| 1571 | |||
| 1534 | /* | 1572 | /* |
| 1535 | * This must be called with current->sighand->siglock held. | 1573 | * This must be called with current->sighand->siglock held. |
| 1536 | * | 1574 | * |
| @@ -1559,11 +1597,7 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) | |||
| 1559 | spin_unlock_irq(¤t->sighand->siglock); | 1597 | spin_unlock_irq(¤t->sighand->siglock); |
| 1560 | try_to_freeze(); | 1598 | try_to_freeze(); |
| 1561 | read_lock(&tasklist_lock); | 1599 | read_lock(&tasklist_lock); |
| 1562 | if (likely(current->ptrace & PT_PTRACED) && | 1600 | if (may_ptrace_stop()) { |
| 1563 | likely(current->parent != current->real_parent || | ||
| 1564 | !(current->ptrace & PT_ATTACHED)) && | ||
| 1565 | (likely(current->parent->signal != current->signal) || | ||
| 1566 | !unlikely(current->signal->flags & SIGNAL_GROUP_EXIT))) { | ||
| 1567 | do_notify_parent_cldstop(current, CLD_TRAPPED); | 1601 | do_notify_parent_cldstop(current, CLD_TRAPPED); |
| 1568 | read_unlock(&tasklist_lock); | 1602 | read_unlock(&tasklist_lock); |
| 1569 | schedule(); | 1603 | schedule(); |
| @@ -2541,6 +2575,11 @@ asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize) | |||
| 2541 | } | 2575 | } |
| 2542 | #endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */ | 2576 | #endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */ |
| 2543 | 2577 | ||
| 2578 | __attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma) | ||
| 2579 | { | ||
| 2580 | return NULL; | ||
| 2581 | } | ||
| 2582 | |||
| 2544 | void __init signals_init(void) | 2583 | void __init signals_init(void) |
| 2545 | { | 2584 | { |
| 2546 | sigqueue_cachep = | 2585 | sigqueue_cachep = |
