Re: [patch 6/9] signal: Fix racy access to __task_cred in kill_pid_info_as_uid()

Oleg Nesterov
2009-12-10T15:17:22Z

On 12/10, Thomas Gleixner wrote:
>
> 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>
> Cc: Oleg Nesterov <oleg@redhat.com>
> ---
> kernel/signal.c | 17 ++++++++++-------
> 1 file changed, 10 insertions(+), 7 deletions(-)

Acked-by: Oleg Nesterov <oleg@redhat.com>

> Index: linux-2.6-tip/kernel/signal.c
> ===================================================================
> --- linux-2.6-tip.orig/kernel/signal.c
> +++ linux-2.6-tip/kernel/signal.c
> @@ -1175,11 +1175,12 @@ int kill_pid_info_as_uid(int sig, struct
> 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
> 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);
>
>