|
@@ -971,6 +971,20 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
|
|
|
return send_signal(sig, info, t, 0);
|
|
|
}
|
|
|
|
|
|
+int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
+ bool group)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ int ret = -ESRCH;
|
|
|
+
|
|
|
+ if (lock_task_sighand(p, &flags)) {
|
|
|
+ ret = send_signal(sig, info, p, group);
|
|
|
+ unlock_task_sighand(p, &flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Force a signal that the process can't ignore: if necessary
|
|
|
* we unblock the signal and change any SIG_IGN to SIG_DFL.
|
|
@@ -1068,18 +1082,10 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long
|
|
|
*/
|
|
|
int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
{
|
|
|
- unsigned long flags;
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = check_kill_permission(sig, info, p);
|
|
|
+ int ret = check_kill_permission(sig, info, p);
|
|
|
|
|
|
- if (!ret && sig) {
|
|
|
- ret = -ESRCH;
|
|
|
- if (lock_task_sighand(p, &flags)) {
|
|
|
- ret = __group_send_sig_info(sig, info, p);
|
|
|
- unlock_task_sighand(p, &flags);
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!ret && sig)
|
|
|
+ ret = do_send_sig_info(sig, info, p, true);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1224,15 +1230,9 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid)
|
|
|
* These are for backward compatibility with the rest of the kernel source.
|
|
|
*/
|
|
|
|
|
|
-/*
|
|
|
- * The caller must ensure the task can't exit.
|
|
|
- */
|
|
|
int
|
|
|
send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
{
|
|
|
- int ret;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
/*
|
|
|
* Make sure legacy kernel users don't send in bad values
|
|
|
* (normal paths check this in check_kill_permission).
|
|
@@ -1240,10 +1240,7 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
if (!valid_signal(sig))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- spin_lock_irqsave(&p->sighand->siglock, flags);
|
|
|
- ret = specific_send_sig_info(sig, info, p);
|
|
|
- spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
|
|
- return ret;
|
|
|
+ return do_send_sig_info(sig, info, p, false);
|
|
|
}
|
|
|
|
|
|
#define __si_special(priv) \
|
|
@@ -2278,7 +2275,6 @@ static int
|
|
|
do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
|
|
|
{
|
|
|
struct task_struct *p;
|
|
|
- unsigned long flags;
|
|
|
int error = -ESRCH;
|
|
|
|
|
|
rcu_read_lock();
|
|
@@ -2288,14 +2284,16 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
|
|
|
/*
|
|
|
* The null signal is a permissions and process existence
|
|
|
* probe. No signal is actually delivered.
|
|
|
- *
|
|
|
- * If lock_task_sighand() fails we pretend the task dies
|
|
|
- * after receiving the signal. The window is tiny, and the
|
|
|
- * signal is private anyway.
|
|
|
*/
|
|
|
- if (!error && sig && lock_task_sighand(p, &flags)) {
|
|
|
- error = specific_send_sig_info(sig, info, p);
|
|
|
- unlock_task_sighand(p, &flags);
|
|
|
+ if (!error && sig) {
|
|
|
+ error = do_send_sig_info(sig, info, p, false);
|
|
|
+ /*
|
|
|
+ * If lock_task_sighand() failed we pretend the task
|
|
|
+ * dies after receiving the signal. The window is tiny,
|
|
|
+ * and the signal is private anyway.
|
|
|
+ */
|
|
|
+ if (unlikely(error == -ESRCH))
|
|
|
+ error = 0;
|
|
|
}
|
|
|
}
|
|
|
rcu_read_unlock();
|