diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 63 |
1 files changed, 53 insertions, 10 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index dbd7fe073c55..906ae5a1779c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -642,7 +642,7 @@ static inline bool si_fromuser(const struct siginfo *info) | |||
642 | static int check_kill_permission(int sig, struct siginfo *info, | 642 | static int check_kill_permission(int sig, struct siginfo *info, |
643 | struct task_struct *t) | 643 | struct task_struct *t) |
644 | { | 644 | { |
645 | const struct cred *cred = current_cred(), *tcred; | 645 | const struct cred *cred, *tcred; |
646 | struct pid *sid; | 646 | struct pid *sid; |
647 | int error; | 647 | int error; |
648 | 648 | ||
@@ -656,8 +656,10 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
656 | if (error) | 656 | if (error) |
657 | return error; | 657 | return error; |
658 | 658 | ||
659 | cred = current_cred(); | ||
659 | tcred = __task_cred(t); | 660 | tcred = __task_cred(t); |
660 | if ((cred->euid ^ tcred->suid) && | 661 | if (!same_thread_group(current, t) && |
662 | (cred->euid ^ tcred->suid) && | ||
661 | (cred->euid ^ tcred->uid) && | 663 | (cred->euid ^ tcred->uid) && |
662 | (cred->uid ^ tcred->suid) && | 664 | (cred->uid ^ tcred->suid) && |
663 | (cred->uid ^ tcred->uid) && | 665 | (cred->uid ^ tcred->uid) && |
@@ -1083,23 +1085,24 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) | |||
1083 | /* | 1085 | /* |
1084 | * Nuke all other threads in the group. | 1086 | * Nuke all other threads in the group. |
1085 | */ | 1087 | */ |
1086 | void zap_other_threads(struct task_struct *p) | 1088 | int zap_other_threads(struct task_struct *p) |
1087 | { | 1089 | { |
1088 | struct task_struct *t; | 1090 | struct task_struct *t = p; |
1091 | int count = 0; | ||
1089 | 1092 | ||
1090 | p->signal->group_stop_count = 0; | 1093 | p->signal->group_stop_count = 0; |
1091 | 1094 | ||
1092 | for (t = next_thread(p); t != p; t = next_thread(t)) { | 1095 | while_each_thread(p, t) { |
1093 | /* | 1096 | count++; |
1094 | * Don't bother with already dead threads | 1097 | |
1095 | */ | 1098 | /* Don't bother with already dead threads */ |
1096 | if (t->exit_state) | 1099 | if (t->exit_state) |
1097 | continue; | 1100 | continue; |
1098 | |||
1099 | /* SIGKILL will be handled before any pending SIGSTOP */ | ||
1100 | sigaddset(&t->pending.signal, SIGKILL); | 1101 | sigaddset(&t->pending.signal, SIGKILL); |
1101 | signal_wake_up(t, 1); | 1102 | signal_wake_up(t, 1); |
1102 | } | 1103 | } |
1104 | |||
1105 | return count; | ||
1103 | } | 1106 | } |
1104 | 1107 | ||
1105 | struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags) | 1108 | struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags) |
@@ -2735,3 +2738,43 @@ void __init signals_init(void) | |||
2735 | { | 2738 | { |
2736 | sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); | 2739 | sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); |
2737 | } | 2740 | } |
2741 | |||
2742 | #ifdef CONFIG_KGDB_KDB | ||
2743 | #include <linux/kdb.h> | ||
2744 | /* | ||
2745 | * kdb_send_sig_info - Allows kdb to send signals without exposing | ||
2746 | * signal internals. This function checks if the required locks are | ||
2747 | * available before calling the main signal code, to avoid kdb | ||
2748 | * deadlocks. | ||
2749 | */ | ||
2750 | void | ||
2751 | kdb_send_sig_info(struct task_struct *t, struct siginfo *info) | ||
2752 | { | ||
2753 | static struct task_struct *kdb_prev_t; | ||
2754 | int sig, new_t; | ||
2755 | if (!spin_trylock(&t->sighand->siglock)) { | ||
2756 | kdb_printf("Can't do kill command now.\n" | ||
2757 | "The sigmask lock is held somewhere else in " | ||
2758 | "kernel, try again later\n"); | ||
2759 | return; | ||
2760 | } | ||
2761 | spin_unlock(&t->sighand->siglock); | ||
2762 | new_t = kdb_prev_t != t; | ||
2763 | kdb_prev_t = t; | ||
2764 | if (t->state != TASK_RUNNING && new_t) { | ||
2765 | kdb_printf("Process is not RUNNING, sending a signal from " | ||
2766 | "kdb risks deadlock\n" | ||
2767 | "on the run queue locks. " | ||
2768 | "The signal has _not_ been sent.\n" | ||
2769 | "Reissue the kill command if you want to risk " | ||
2770 | "the deadlock.\n"); | ||
2771 | return; | ||
2772 | } | ||
2773 | sig = info->si_signo; | ||
2774 | if (send_sig_info(sig, info, t)) | ||
2775 | kdb_printf("Fail to deliver Signal %d to process %d.\n", | ||
2776 | sig, t->pid); | ||
2777 | else | ||
2778 | kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid); | ||
2779 | } | ||
2780 | #endif /* CONFIG_KGDB_KDB */ | ||