diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-19 12:47:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-19 12:47:34 -0500 |
commit | 10e5453ffa0d04a2eda3cda3f55b88cb9c04595f (patch) | |
tree | def247dc399549bc1359fe9d1faa49c621f8890d /kernel/signal.c | |
parent | 3cd312c3e887b4bee2d94668a481b3d19c07732c (diff) | |
parent | d4581a239a40319205762b76c01eb6363f277efa (diff) |
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()
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 1814e68e4de3..d09692b40376 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -218,13 +218,13 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi | |||
218 | struct user_struct *user; | 218 | struct user_struct *user; |
219 | 219 | ||
220 | /* | 220 | /* |
221 | * We won't get problems with the target's UID changing under us | 221 | * Protect access to @t credentials. This can go away when all |
222 | * because changing it requires RCU be used, and if t != current, the | 222 | * callers hold rcu read lock. |
223 | * caller must be holding the RCU readlock (by way of a spinlock) and | ||
224 | * we use RCU protection here | ||
225 | */ | 223 | */ |
224 | rcu_read_lock(); | ||
226 | user = get_uid(__task_cred(t)->user); | 225 | user = get_uid(__task_cred(t)->user); |
227 | atomic_inc(&user->sigpending); | 226 | atomic_inc(&user->sigpending); |
227 | rcu_read_unlock(); | ||
228 | 228 | ||
229 | if (override_rlimit || | 229 | if (override_rlimit || |
230 | atomic_read(&user->sigpending) <= | 230 | atomic_read(&user->sigpending) <= |
@@ -1179,11 +1179,12 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1179 | int ret = -EINVAL; | 1179 | int ret = -EINVAL; |
1180 | struct task_struct *p; | 1180 | struct task_struct *p; |
1181 | const struct cred *pcred; | 1181 | const struct cred *pcred; |
1182 | unsigned long flags; | ||
1182 | 1183 | ||
1183 | if (!valid_signal(sig)) | 1184 | if (!valid_signal(sig)) |
1184 | return ret; | 1185 | return ret; |
1185 | 1186 | ||
1186 | read_lock(&tasklist_lock); | 1187 | rcu_read_lock(); |
1187 | p = pid_task(pid, PIDTYPE_PID); | 1188 | p = pid_task(pid, PIDTYPE_PID); |
1188 | if (!p) { | 1189 | if (!p) { |
1189 | ret = -ESRCH; | 1190 | ret = -ESRCH; |
@@ -1199,14 +1200,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1199 | ret = security_task_kill(p, info, sig, secid); | 1200 | ret = security_task_kill(p, info, sig, secid); |
1200 | if (ret) | 1201 | if (ret) |
1201 | goto out_unlock; | 1202 | goto out_unlock; |
1202 | if (sig && p->sighand) { | 1203 | |
1203 | unsigned long flags; | 1204 | if (sig) { |
1204 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1205 | if (lock_task_sighand(p, &flags)) { |
1205 | ret = __send_signal(sig, info, p, 1, 0); | 1206 | ret = __send_signal(sig, info, p, 1, 0); |
1206 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 1207 | unlock_task_sighand(p, &flags); |
1208 | } else | ||
1209 | ret = -ESRCH; | ||
1207 | } | 1210 | } |
1208 | out_unlock: | 1211 | out_unlock: |
1209 | read_unlock(&tasklist_lock); | 1212 | rcu_read_unlock(); |
1210 | return ret; | 1213 | return ret; |
1211 | } | 1214 | } |
1212 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); | 1215 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); |