aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2009-12-09 19:53:17 -0500
committerThomas Gleixner <tglx@linutronix.de>2009-12-10 17:04:11 -0500
commit14d8c9f3c09e7fd7b9af80904289fe204f5b93c6 (patch)
tree1c373436517c5853aab0e99cce83364a21134d0e /kernel/signal.c
parentea5b41f9d595be354f7a50e56b28c2d72e6e88a5 (diff)
signal: Fix racy access to __task_cred in kill_pid_info_as_uid()
kill_pid_info_as_uid() accesses __task_cred() without being in a RCU read side critical section. tasklist_lock is not protecting that when CONFIG_TREE_PREEMPT_RCU=y. Convert the whole tasklist_lock section to rcu and use lock_task_sighand to prevent the exit race. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> LKML-Reference: <20091210004703.232302055@linutronix.de> Acked-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 6b982f2cf524..73316568a69c 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1175,11 +1175,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
1175 int ret = -EINVAL; 1175 int ret = -EINVAL;
1176 struct task_struct *p; 1176 struct task_struct *p;
1177 const struct cred *pcred; 1177 const struct cred *pcred;
1178 unsigned long flags;
1178 1179
1179 if (!valid_signal(sig)) 1180 if (!valid_signal(sig))
1180 return ret; 1181 return ret;
1181 1182
1182 read_lock(&tasklist_lock); 1183 rcu_read_lock();
1183 p = pid_task(pid, PIDTYPE_PID); 1184 p = pid_task(pid, PIDTYPE_PID);
1184 if (!p) { 1185 if (!p) {
1185 ret = -ESRCH; 1186 ret = -ESRCH;
@@ -1196,14 +1197,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
1196 ret = security_task_kill(p, info, sig, secid); 1197 ret = security_task_kill(p, info, sig, secid);
1197 if (ret) 1198 if (ret)
1198 goto out_unlock; 1199 goto out_unlock;
1199 if (sig && p->sighand) { 1200
1200 unsigned long flags; 1201 if (sig) {
1201 spin_lock_irqsave(&p->sighand->siglock, flags); 1202 if (lock_task_sighand(p, &flags)) {
1202 ret = __send_signal(sig, info, p, 1, 0); 1203 ret = __send_signal(sig, info, p, 1, 0);
1203 spin_unlock_irqrestore(&p->sighand->siglock, flags); 1204 unlock_task_sighand(p, &flags);
1205 } else
1206 ret = -ESRCH;
1204 } 1207 }
1205out_unlock: 1208out_unlock:
1206 read_unlock(&tasklist_lock); 1209 rcu_read_unlock();
1207 return ret; 1210 return ret;
1208} 1211}
1209EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); 1212EXPORT_SYMBOL_GPL(kill_pid_info_as_uid);