* '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()
Unified · Split
| @@ -218,13 +218,13 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi · 217 unmodified lines | ||
| 218 | 218 | struct user_struct *user; |
| 219 | 219 | |
| 220 | 220 | /* |
| 221 | − * We won't get problems with the target's UID changing under us | |
| 222 | − * because changing it requires RCU be used, and if t != current, the | |
| 223 | − * caller must be holding the RCU readlock (by way of a spinlock) and | |
| 224 | − * we use RCU protection here | |
| 221 | + * Protect access to @t credentials. This can go away when all | |
| 222 | + * callers hold rcu read lock. | |
| 225 | 223 | */ |
| 224 | + rcu_read_lock(); | |
| 226 | 225 | user = get_uid(__task_cred(t)->user); |
| 227 | 226 | atomic_inc(&user->sigpending); |
| 227 | + rcu_read_unlock(); | |
| 228 | 228 | |
| 229 | 229 | if (override_rlimit || |
| 230 | 230 | atomic_read(&user->sigpending) <= |
| @@ -1179,11 +1179,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, · 948 unmodified lines | ||
| 1179 | 1179 | int ret = -EINVAL; |
| 1180 | 1180 | struct task_struct *p; |
| 1181 | 1181 | const struct cred *pcred; |
| 1182 | + unsigned long flags; | |
| 1182 | 1183 | |
| 1183 | 1184 | if (!valid_signal(sig)) |
| 1184 | 1185 | return ret; |
| 1185 | 1186 | |
| 1186 | − read_lock(&tasklist_lock); | |
| 1187 | + rcu_read_lock(); | |
| 1187 | 1188 | p = pid_task(pid, PIDTYPE_PID); |
| 1188 | 1189 | if (!p) { |
| 1189 | 1190 | ret = -ESRCH; |
| @@ -1199,14 +1200,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, · 9 unmodified lines | ||
| 1199 | 1200 | ret = security_task_kill(p, info, sig, secid); |
| 1200 | 1201 | if (ret) |
| 1201 | 1202 | goto out_unlock; |
| 1202 | − if (sig && p->sighand) { | |
| 1203 | − unsigned long flags; | |
| 1204 | − spin_lock_irqsave(&p->sighand->siglock, flags); | |
| 1205 | − ret = __send_signal(sig, info, p, 1, 0); | |
| 1206 | − spin_unlock_irqrestore(&p->sighand->siglock, flags); | |
| 1203 | + | |
| 1204 | + if (sig) { | |
| 1205 | + if (lock_task_sighand(p, &flags)) { | |
| 1206 | + ret = __send_signal(sig, info, p, 1, 0); | |
| 1207 | + unlock_task_sighand(p, &flags); | |
| 1208 | + } else | |
| 1209 | + ret = -ESRCH; | |
| 1207 | 1210 | } |
| 1208 | 1211 | out_unlock: |
| 1209 | − read_unlock(&tasklist_lock); | |
| 1212 | + rcu_read_unlock(); | |
| 1210 | 1213 | return ret; |
| 1211 | 1214 | } |
| 1212 | 1215 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); |
| @@ -162,6 +162,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) · 161 unmodified lines | ||
| 162 | 162 | if (niceval > 19) |
| 163 | 163 | niceval = 19; |
| 164 | 164 | |
| 165 | + rcu_read_lock(); | |
| 165 | 166 | read_lock(&tasklist_lock); |
| 166 | 167 | switch (which) { |
| 167 | 168 | case PRIO_PROCESS: |
| @@ -199,6 +200,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) · 31 unmodified lines | ||
| 199 | 200 | } |
| 200 | 201 | out_unlock: |
| 201 | 202 | read_unlock(&tasklist_lock); |
| 203 | + rcu_read_unlock(); | |
| 202 | 204 | out: |
| 203 | 205 | return error; |
| 204 | 206 | } |