Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  sys: Fix missing rcu protection for __task_cred() access
  signals: Fix more rcu assumptions
  signal: Fix racy access to __task_cred in kill_pid_info_as_uid()
This commit is contained in:
Linus Torvalds 2009-12-19 09:47:34 -08:00
commit 10e5453ffa
2 changed files with 16 additions and 11 deletions

View file

@ -218,13 +218,13 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi
struct user_struct *user; struct user_struct *user;
/* /*
* We won't get problems with the target's UID changing under us * Protect access to @t credentials. This can go away when all
* because changing it requires RCU be used, and if t != current, the * callers hold rcu read lock.
* caller must be holding the RCU readlock (by way of a spinlock) and
* we use RCU protection here
*/ */
rcu_read_lock();
user = get_uid(__task_cred(t)->user); user = get_uid(__task_cred(t)->user);
atomic_inc(&user->sigpending); atomic_inc(&user->sigpending);
rcu_read_unlock();
if (override_rlimit || if (override_rlimit ||
atomic_read(&user->sigpending) <= atomic_read(&user->sigpending) <=
@ -1179,11 +1179,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
int ret = -EINVAL; int ret = -EINVAL;
struct task_struct *p; struct task_struct *p;
const struct cred *pcred; const struct cred *pcred;
unsigned long flags;
if (!valid_signal(sig)) if (!valid_signal(sig))
return ret; return ret;
read_lock(&tasklist_lock); rcu_read_lock();
p = pid_task(pid, PIDTYPE_PID); p = pid_task(pid, PIDTYPE_PID);
if (!p) { if (!p) {
ret = -ESRCH; ret = -ESRCH;
@ -1199,14 +1200,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
ret = security_task_kill(p, info, sig, secid); ret = security_task_kill(p, info, sig, secid);
if (ret) if (ret)
goto out_unlock; goto out_unlock;
if (sig && p->sighand) {
unsigned long flags; if (sig) {
spin_lock_irqsave(&p->sighand->siglock, flags); if (lock_task_sighand(p, &flags)) {
ret = __send_signal(sig, info, p, 1, 0); ret = __send_signal(sig, info, p, 1, 0);
spin_unlock_irqrestore(&p->sighand->siglock, flags); unlock_task_sighand(p, &flags);
} else
ret = -ESRCH;
} }
out_unlock: out_unlock:
read_unlock(&tasklist_lock); rcu_read_unlock();
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); EXPORT_SYMBOL_GPL(kill_pid_info_as_uid);

View file

@ -162,6 +162,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
if (niceval > 19) if (niceval > 19)
niceval = 19; niceval = 19;
rcu_read_lock();
read_lock(&tasklist_lock); read_lock(&tasklist_lock);
switch (which) { switch (which) {
case PRIO_PROCESS: case PRIO_PROCESS:
@ -199,6 +200,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
} }
out_unlock: out_unlock:
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
rcu_read_unlock();
out: out:
return error; return error;
} }