diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index b3dedf1f932..13371d17358 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -2219,6 +2219,7 @@ static int do_tkill(int tgid, int pid, int sig) | |||
2219 | int error; | 2219 | int error; |
2220 | struct siginfo info; | 2220 | struct siginfo info; |
2221 | struct task_struct *p; | 2221 | struct task_struct *p; |
2222 | unsigned long flags; | ||
2222 | 2223 | ||
2223 | error = -ESRCH; | 2224 | error = -ESRCH; |
2224 | info.si_signo = sig; | 2225 | info.si_signo = sig; |
@@ -2227,21 +2228,24 @@ static int do_tkill(int tgid, int pid, int sig) | |||
2227 | info.si_pid = task_tgid_vnr(current); | 2228 | info.si_pid = task_tgid_vnr(current); |
2228 | info.si_uid = current->uid; | 2229 | info.si_uid = current->uid; |
2229 | 2230 | ||
2230 | read_lock(&tasklist_lock); | 2231 | rcu_read_lock(); |
2231 | p = find_task_by_vpid(pid); | 2232 | p = find_task_by_vpid(pid); |
2232 | if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { | 2233 | if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { |
2233 | error = check_kill_permission(sig, &info, p); | 2234 | error = check_kill_permission(sig, &info, p); |
2234 | /* | 2235 | /* |
2235 | * The null signal is a permissions and process existence | 2236 | * The null signal is a permissions and process existence |
2236 | * probe. No signal is actually delivered. | 2237 | * probe. No signal is actually delivered. |
2238 | * | ||
2239 | * If lock_task_sighand() fails we pretend the task dies | ||
2240 | * after receiving the signal. The window is tiny, and the | ||
2241 | * signal is private anyway. | ||
2237 | */ | 2242 | */ |
2238 | if (!error && sig && p->sighand) { | 2243 | if (!error && sig && lock_task_sighand(p, &flags)) { |
2239 | spin_lock_irq(&p->sighand->siglock); | ||
2240 | error = specific_send_sig_info(sig, &info, p); | 2244 | error = specific_send_sig_info(sig, &info, p); |
2241 | spin_unlock_irq(&p->sighand->siglock); | 2245 | unlock_task_sighand(p, &flags); |
2242 | } | 2246 | } |
2243 | } | 2247 | } |
2244 | read_unlock(&tasklist_lock); | 2248 | rcu_read_unlock(); |
2245 | 2249 | ||
2246 | return error; | 2250 | return error; |
2247 | } | 2251 | } |