diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:19 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:19 -0500 |
commit | c69e8d9c01db2adc503464993c358901c9af9de4 (patch) | |
tree | bed94aaa9aeb7a7834d1c880f72b62a11a752c78 /fs/proc/array.c | |
parent | 86a264abe542cfececb4df129bc45a0338d8cdb9 (diff) |
CRED: Use RCU to access another task's creds and to release a task's own creds
Use RCU to access another task's creds and to release a task's own creds.
This means that it will be possible for the credentials of a task to be
replaced without another task (a) requiring a full lock to read them, and (b)
seeing deallocated memory.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: James Morris <jmorris@namei.org>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'fs/proc/array.c')
-rw-r--r-- | fs/proc/array.c | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 62fe9b2009b6..7e4877d9dcb5 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -159,6 +159,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
159 | struct group_info *group_info; | 159 | struct group_info *group_info; |
160 | int g; | 160 | int g; |
161 | struct fdtable *fdt = NULL; | 161 | struct fdtable *fdt = NULL; |
162 | const struct cred *cred; | ||
162 | pid_t ppid, tpid; | 163 | pid_t ppid, tpid; |
163 | 164 | ||
164 | rcu_read_lock(); | 165 | rcu_read_lock(); |
@@ -170,6 +171,7 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
170 | if (tracer) | 171 | if (tracer) |
171 | tpid = task_pid_nr_ns(tracer, ns); | 172 | tpid = task_pid_nr_ns(tracer, ns); |
172 | } | 173 | } |
174 | cred = get_cred((struct cred *) __task_cred(p)); | ||
173 | seq_printf(m, | 175 | seq_printf(m, |
174 | "State:\t%s\n" | 176 | "State:\t%s\n" |
175 | "Tgid:\t%d\n" | 177 | "Tgid:\t%d\n" |
@@ -182,8 +184,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
182 | task_tgid_nr_ns(p, ns), | 184 | task_tgid_nr_ns(p, ns), |
183 | pid_nr_ns(pid, ns), | 185 | pid_nr_ns(pid, ns), |
184 | ppid, tpid, | 186 | ppid, tpid, |
185 | p->cred->uid, p->cred->euid, p->cred->suid, p->cred->fsuid, | 187 | cred->uid, cred->euid, cred->suid, cred->fsuid, |
186 | p->cred->gid, p->cred->egid, p->cred->sgid, p->cred->fsgid); | 188 | cred->gid, cred->egid, cred->sgid, cred->fsgid); |
187 | 189 | ||
188 | task_lock(p); | 190 | task_lock(p); |
189 | if (p->files) | 191 | if (p->files) |
@@ -194,13 +196,12 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
194 | fdt ? fdt->max_fds : 0); | 196 | fdt ? fdt->max_fds : 0); |
195 | rcu_read_unlock(); | 197 | rcu_read_unlock(); |
196 | 198 | ||
197 | group_info = p->cred->group_info; | 199 | group_info = cred->group_info; |
198 | get_group_info(group_info); | ||
199 | task_unlock(p); | 200 | task_unlock(p); |
200 | 201 | ||
201 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) | 202 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) |
202 | seq_printf(m, "%d ", GROUP_AT(group_info, g)); | 203 | seq_printf(m, "%d ", GROUP_AT(group_info, g)); |
203 | put_group_info(group_info); | 204 | put_cred(cred); |
204 | 205 | ||
205 | seq_printf(m, "\n"); | 206 | seq_printf(m, "\n"); |
206 | } | 207 | } |
@@ -262,7 +263,7 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) | |||
262 | blocked = p->blocked; | 263 | blocked = p->blocked; |
263 | collect_sigign_sigcatch(p, &ignored, &caught); | 264 | collect_sigign_sigcatch(p, &ignored, &caught); |
264 | num_threads = atomic_read(&p->signal->count); | 265 | num_threads = atomic_read(&p->signal->count); |
265 | qsize = atomic_read(&p->cred->user->sigpending); | 266 | qsize = atomic_read(&__task_cred(p)->user->sigpending); |
266 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; | 267 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; |
267 | unlock_task_sighand(p, &flags); | 268 | unlock_task_sighand(p, &flags); |
268 | } | 269 | } |
@@ -293,12 +294,21 @@ static void render_cap_t(struct seq_file *m, const char *header, | |||
293 | 294 | ||
294 | static inline void task_cap(struct seq_file *m, struct task_struct *p) | 295 | static inline void task_cap(struct seq_file *m, struct task_struct *p) |
295 | { | 296 | { |
296 | struct cred *cred = p->cred; | 297 | const struct cred *cred; |
298 | kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset; | ||
297 | 299 | ||
298 | render_cap_t(m, "CapInh:\t", &cred->cap_inheritable); | 300 | rcu_read_lock(); |
299 | render_cap_t(m, "CapPrm:\t", &cred->cap_permitted); | 301 | cred = __task_cred(p); |
300 | render_cap_t(m, "CapEff:\t", &cred->cap_effective); | 302 | cap_inheritable = cred->cap_inheritable; |
301 | render_cap_t(m, "CapBnd:\t", &cred->cap_bset); | 303 | cap_permitted = cred->cap_permitted; |
304 | cap_effective = cred->cap_effective; | ||
305 | cap_bset = cred->cap_bset; | ||
306 | rcu_read_unlock(); | ||
307 | |||
308 | render_cap_t(m, "CapInh:\t", &cap_inheritable); | ||
309 | render_cap_t(m, "CapPrm:\t", &cap_permitted); | ||
310 | render_cap_t(m, "CapEff:\t", &cap_effective); | ||
311 | render_cap_t(m, "CapBnd:\t", &cap_bset); | ||
302 | } | 312 | } |
303 | 313 | ||
304 | static inline void task_context_switch_counts(struct seq_file *m, | 314 | static inline void task_context_switch_counts(struct seq_file *m, |