diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-05-31 19:26:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-31 20:49:28 -0400 |
commit | 43e13cc107cf6cd3c15fbe1cef849435c2223d50 (patch) | |
tree | 9a1b3aa79ec2e8374944c23cf57a73790a3fc6ce | |
parent | 9b3c98cd663750c33434572ff76ba306505eba5a (diff) |
cred: remove task_is_dead() from __task_cred() validation
Commit 8f92054e7ca1 ("CRED: Fix __task_cred()'s lockdep check and banner
comment"):
add the following validation condition:
task->exit_state >= 0
to permit the access if the target task is dead and therefore
unable to change its own credentials.
OK, but afaics currently this can only help wait_task_zombie() which calls
__task_cred() without rcu lock.
Remove this validation and change wait_task_zombie() to use task_uid()
instead. This means we do rcu_read_lock() only to shut up the lockdep,
but we already do the same in, say, wait_task_stopped().
task_is_dead() should die, task->exit_state != 0 means that this task has
passed exit_notify(), only do_wait-like code paths should use this.
Unfortunately, we can't kill task_is_dead() right now, it has already
acquired buggy users in drivers/staging. The fix already exists.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: David Howells <dhowells@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: James Morris <jmorris@namei.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/cred.h | 10 | ||||
-rw-r--r-- | kernel/exit.c | 2 |
2 files changed, 4 insertions, 8 deletions
diff --git a/include/linux/cred.h b/include/linux/cred.h index 917dc5aeb1d4..ebbed2ce6637 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
@@ -277,17 +277,13 @@ static inline void put_cred(const struct cred *_cred) | |||
277 | * @task: The task to query | 277 | * @task: The task to query |
278 | * | 278 | * |
279 | * Access the objective credentials of a task. The caller must hold the RCU | 279 | * Access the objective credentials of a task. The caller must hold the RCU |
280 | * readlock or the task must be dead and unable to change its own credentials. | 280 | * readlock. |
281 | * | 281 | * |
282 | * The result of this function should not be passed directly to get_cred(); | 282 | * The result of this function should not be passed directly to get_cred(); |
283 | * rather get_task_cred() should be used instead. | 283 | * rather get_task_cred() should be used instead. |
284 | */ | 284 | */ |
285 | #define __task_cred(task) \ | 285 | #define __task_cred(task) \ |
286 | ({ \ | 286 | rcu_dereference((task)->real_cred) |
287 | const struct task_struct *__t = (task); \ | ||
288 | rcu_dereference_check(__t->real_cred, \ | ||
289 | task_is_dead(__t)); \ | ||
290 | }) | ||
291 | 287 | ||
292 | /** | 288 | /** |
293 | * get_current_cred - Get the current task's subjective credentials | 289 | * get_current_cred - Get the current task's subjective credentials |
diff --git a/kernel/exit.c b/kernel/exit.c index 910a0716e17a..3281493ce7ad 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -1214,7 +1214,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1214 | unsigned long state; | 1214 | unsigned long state; |
1215 | int retval, status, traced; | 1215 | int retval, status, traced; |
1216 | pid_t pid = task_pid_vnr(p); | 1216 | pid_t pid = task_pid_vnr(p); |
1217 | uid_t uid = from_kuid_munged(current_user_ns(), __task_cred(p)->uid); | 1217 | uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p)); |
1218 | struct siginfo __user *infop; | 1218 | struct siginfo __user *infop; |
1219 | 1219 | ||
1220 | if (!likely(wo->wo_flags & WEXITED)) | 1220 | if (!likely(wo->wo_flags & WEXITED)) |