diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 53 |
1 files changed, 38 insertions, 15 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 619b027e92b5..f2b96b08fb44 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -262,7 +262,7 @@ next_signal(struct sigpending *pending, sigset_t *mask) | |||
262 | return sig; | 262 | return sig; |
263 | } | 263 | } |
264 | 264 | ||
265 | static struct sigqueue *__sigqueue_alloc(struct task_struct *t, unsigned int __nocast flags, | 265 | static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, |
266 | int override_rlimit) | 266 | int override_rlimit) |
267 | { | 267 | { |
268 | struct sigqueue *q = NULL; | 268 | struct sigqueue *q = NULL; |
@@ -397,20 +397,8 @@ void __exit_signal(struct task_struct *tsk) | |||
397 | flush_sigqueue(&tsk->pending); | 397 | flush_sigqueue(&tsk->pending); |
398 | if (sig) { | 398 | if (sig) { |
399 | /* | 399 | /* |
400 | * We are cleaning up the signal_struct here. We delayed | 400 | * We are cleaning up the signal_struct here. |
401 | * calling exit_itimers until after flush_sigqueue, just in | ||
402 | * case our thread-local pending queue contained a queued | ||
403 | * timer signal that would have been cleared in | ||
404 | * exit_itimers. When that called sigqueue_free, it would | ||
405 | * attempt to re-take the tasklist_lock and deadlock. This | ||
406 | * can never happen if we ensure that all queues the | ||
407 | * timer's signal might be queued on have been flushed | ||
408 | * first. The shared_pending queue, and our own pending | ||
409 | * queue are the only queues the timer could be on, since | ||
410 | * there are no other threads left in the group and timer | ||
411 | * signals are constrained to threads inside the group. | ||
412 | */ | 401 | */ |
413 | exit_itimers(sig); | ||
414 | exit_thread_group_keys(sig); | 402 | exit_thread_group_keys(sig); |
415 | kmem_cache_free(signal_cachep, sig); | 403 | kmem_cache_free(signal_cachep, sig); |
416 | } | 404 | } |
@@ -578,7 +566,8 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) | |||
578 | * is to alert stop-signal processing code when another | 566 | * is to alert stop-signal processing code when another |
579 | * processor has come along and cleared the flag. | 567 | * processor has come along and cleared the flag. |
580 | */ | 568 | */ |
581 | tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; | 569 | if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) |
570 | tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; | ||
582 | } | 571 | } |
583 | if ( signr && | 572 | if ( signr && |
584 | ((info->si_code & __SI_MASK) == __SI_TIMER) && | 573 | ((info->si_code & __SI_MASK) == __SI_TIMER) && |
@@ -1192,6 +1181,40 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid) | |||
1192 | return error; | 1181 | return error; |
1193 | } | 1182 | } |
1194 | 1183 | ||
1184 | /* like kill_proc_info(), but doesn't use uid/euid of "current" */ | ||
1185 | int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid, | ||
1186 | uid_t uid, uid_t euid) | ||
1187 | { | ||
1188 | int ret = -EINVAL; | ||
1189 | struct task_struct *p; | ||
1190 | |||
1191 | if (!valid_signal(sig)) | ||
1192 | return ret; | ||
1193 | |||
1194 | read_lock(&tasklist_lock); | ||
1195 | p = find_task_by_pid(pid); | ||
1196 | if (!p) { | ||
1197 | ret = -ESRCH; | ||
1198 | goto out_unlock; | ||
1199 | } | ||
1200 | if ((!info || ((unsigned long)info != 1 && | ||
1201 | (unsigned long)info != 2 && SI_FROMUSER(info))) | ||
1202 | && (euid != p->suid) && (euid != p->uid) | ||
1203 | && (uid != p->suid) && (uid != p->uid)) { | ||
1204 | ret = -EPERM; | ||
1205 | goto out_unlock; | ||
1206 | } | ||
1207 | if (sig && p->sighand) { | ||
1208 | unsigned long flags; | ||
1209 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
1210 | ret = __group_send_sig_info(sig, info, p); | ||
1211 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
1212 | } | ||
1213 | out_unlock: | ||
1214 | read_unlock(&tasklist_lock); | ||
1215 | return ret; | ||
1216 | } | ||
1217 | EXPORT_SYMBOL_GPL(kill_proc_info_as_uid); | ||
1195 | 1218 | ||
1196 | /* | 1219 | /* |
1197 | * kill_something_info() interprets pid in interesting ways just like kill(2). | 1220 | * kill_something_info() interprets pid in interesting ways just like kill(2). |