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>
This commit is contained in:
parent
ea5b41f9d5
commit
14d8c9f3c0
|
@ -1175,11 +1175,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
|
|||
int ret = -EINVAL;
|
||||
struct task_struct *p;
|
||||
const struct cred *pcred;
|
||||
unsigned long flags;
|
||||
|
||||
if (!valid_signal(sig))
|
||||
return ret;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
rcu_read_lock();
|
||||
p = pid_task(pid, PIDTYPE_PID);
|
||||
if (!p) {
|
||||
ret = -ESRCH;
|
||||
|
@ -1196,14 +1197,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
|
|||
ret = security_task_kill(p, info, sig, secid);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
if (sig && p->sighand) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&p->sighand->siglock, flags);
|
||||
ret = __send_signal(sig, info, p, 1, 0);
|
||||
spin_unlock_irqrestore(&p->sighand->siglock, flags);
|
||||
|
||||
if (sig) {
|
||||
if (lock_task_sighand(p, &flags)) {
|
||||
ret = __send_signal(sig, info, p, 1, 0);
|
||||
unlock_task_sighand(p, &flags);
|
||||
} else
|
||||
ret = -ESRCH;
|
||||
}
|
||||
out_unlock:
|
||||
read_unlock(&tasklist_lock);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kill_pid_info_as_uid);
|
||||
|
|
Loading…
Reference in New Issue