diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:26 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:26 -0500 |
commit | 3b11a1decef07c19443d24ae926982bc8ec9f4c0 (patch) | |
tree | b6555f0e5b07f4b2badd332a0a900b974920c49d /kernel | |
parent | 98870ab0a5a3f1822aee681d2997017e1c87d026 (diff) |
CRED: Differentiate objective and effective subjective credentials on a task
Differentiate the objective and real subjective credentials from the effective
subjective credentials on a task by introducing a second credentials pointer
into the task_struct.
task_struct::real_cred then refers to the objective and apparent real
subjective credentials of a task, as perceived by the other tasks in the
system.
task_struct::cred then refers to the effective subjective credentials of a
task, as used by that task when it's actually running. These are not visible
to the other tasks in the system.
__task_cred(task) then refers to the objective/real credentials of the task in
question.
current_cred() refers to the effective subjective credentials of the current
task.
prepare_creds() uses the objective creds as a base and commit_creds() changes
both pointers in the task_struct (indeed commit_creds() requires them to be the
same).
override_creds() and revert_creds() change the subjective creds pointer only,
and the former returns the old subjective creds. These are used by NFSD,
faccessat() and do_coredump(), and will by used by CacheFiles.
In SELinux, current_has_perm() is provided as an alternative to
task_has_perm(). This uses the effective subjective context of current,
whereas task_has_perm() uses the objective/real context of the subject.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cred.c | 38 | ||||
-rw-r--r-- | kernel/fork.c | 6 |
2 files changed, 30 insertions, 14 deletions
diff --git a/kernel/cred.c b/kernel/cred.c index b8bd2f99d8ce..f3ca10660617 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
@@ -35,7 +35,7 @@ static struct thread_group_cred init_tgcred = { | |||
35 | * The initial credentials for the initial task | 35 | * The initial credentials for the initial task |
36 | */ | 36 | */ |
37 | struct cred init_cred = { | 37 | struct cred init_cred = { |
38 | .usage = ATOMIC_INIT(3), | 38 | .usage = ATOMIC_INIT(4), |
39 | .securebits = SECUREBITS_DEFAULT, | 39 | .securebits = SECUREBITS_DEFAULT, |
40 | .cap_inheritable = CAP_INIT_INH_SET, | 40 | .cap_inheritable = CAP_INIT_INH_SET, |
41 | .cap_permitted = CAP_FULL_SET, | 41 | .cap_permitted = CAP_FULL_SET, |
@@ -120,6 +120,8 @@ EXPORT_SYMBOL(__put_cred); | |||
120 | * prepare a new copy, which the caller then modifies and then commits by | 120 | * prepare a new copy, which the caller then modifies and then commits by |
121 | * calling commit_creds(). | 121 | * calling commit_creds(). |
122 | * | 122 | * |
123 | * Preparation involves making a copy of the objective creds for modification. | ||
124 | * | ||
123 | * Returns a pointer to the new creds-to-be if successful, NULL otherwise. | 125 | * Returns a pointer to the new creds-to-be if successful, NULL otherwise. |
124 | * | 126 | * |
125 | * Call commit_creds() or abort_creds() to clean up. | 127 | * Call commit_creds() or abort_creds() to clean up. |
@@ -130,7 +132,7 @@ struct cred *prepare_creds(void) | |||
130 | const struct cred *old; | 132 | const struct cred *old; |
131 | struct cred *new; | 133 | struct cred *new; |
132 | 134 | ||
133 | BUG_ON(atomic_read(&task->cred->usage) < 1); | 135 | BUG_ON(atomic_read(&task->real_cred->usage) < 1); |
134 | 136 | ||
135 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); | 137 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); |
136 | if (!new) | 138 | if (!new) |
@@ -262,6 +264,9 @@ error: | |||
262 | * | 264 | * |
263 | * We share if we can, but under some circumstances we have to generate a new | 265 | * We share if we can, but under some circumstances we have to generate a new |
264 | * set. | 266 | * set. |
267 | * | ||
268 | * The new process gets the current process's subjective credentials as its | ||
269 | * objective and subjective credentials | ||
265 | */ | 270 | */ |
266 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | 271 | int copy_creds(struct task_struct *p, unsigned long clone_flags) |
267 | { | 272 | { |
@@ -278,6 +283,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
278 | #endif | 283 | #endif |
279 | clone_flags & CLONE_THREAD | 284 | clone_flags & CLONE_THREAD |
280 | ) { | 285 | ) { |
286 | p->real_cred = get_cred(p->cred); | ||
281 | get_cred(p->cred); | 287 | get_cred(p->cred); |
282 | atomic_inc(&p->cred->user->processes); | 288 | atomic_inc(&p->cred->user->processes); |
283 | return 0; | 289 | return 0; |
@@ -317,7 +323,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
317 | #endif | 323 | #endif |
318 | 324 | ||
319 | atomic_inc(&new->user->processes); | 325 | atomic_inc(&new->user->processes); |
320 | p->cred = new; | 326 | p->cred = p->real_cred = get_cred(new); |
321 | return 0; | 327 | return 0; |
322 | } | 328 | } |
323 | 329 | ||
@@ -326,7 +332,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
326 | * @new: The credentials to be assigned | 332 | * @new: The credentials to be assigned |
327 | * | 333 | * |
328 | * Install a new set of credentials to the current task, using RCU to replace | 334 | * Install a new set of credentials to the current task, using RCU to replace |
329 | * the old set. | 335 | * the old set. Both the objective and the subjective credentials pointers are |
336 | * updated. This function may not be called if the subjective credentials are | ||
337 | * in an overridden state. | ||
330 | * | 338 | * |
331 | * This function eats the caller's reference to the new credentials. | 339 | * This function eats the caller's reference to the new credentials. |
332 | * | 340 | * |
@@ -338,12 +346,15 @@ int commit_creds(struct cred *new) | |||
338 | struct task_struct *task = current; | 346 | struct task_struct *task = current; |
339 | const struct cred *old; | 347 | const struct cred *old; |
340 | 348 | ||
349 | BUG_ON(task->cred != task->real_cred); | ||
350 | BUG_ON(atomic_read(&task->real_cred->usage) < 2); | ||
341 | BUG_ON(atomic_read(&new->usage) < 1); | 351 | BUG_ON(atomic_read(&new->usage) < 1); |
342 | BUG_ON(atomic_read(&task->cred->usage) < 1); | ||
343 | 352 | ||
344 | old = task->cred; | 353 | old = task->real_cred; |
345 | security_commit_creds(new, old); | 354 | security_commit_creds(new, old); |
346 | 355 | ||
356 | get_cred(new); /* we will require a ref for the subj creds too */ | ||
357 | |||
347 | /* dumpability changes */ | 358 | /* dumpability changes */ |
348 | if (old->euid != new->euid || | 359 | if (old->euid != new->euid || |
349 | old->egid != new->egid || | 360 | old->egid != new->egid || |
@@ -369,6 +380,7 @@ int commit_creds(struct cred *new) | |||
369 | */ | 380 | */ |
370 | if (new->user != old->user) | 381 | if (new->user != old->user) |
371 | atomic_inc(&new->user->processes); | 382 | atomic_inc(&new->user->processes); |
383 | rcu_assign_pointer(task->real_cred, new); | ||
372 | rcu_assign_pointer(task->cred, new); | 384 | rcu_assign_pointer(task->cred, new); |
373 | if (new->user != old->user) | 385 | if (new->user != old->user) |
374 | atomic_dec(&old->user->processes); | 386 | atomic_dec(&old->user->processes); |
@@ -388,6 +400,8 @@ int commit_creds(struct cred *new) | |||
388 | new->fsgid != old->fsgid) | 400 | new->fsgid != old->fsgid) |
389 | proc_id_connector(task, PROC_EVENT_GID); | 401 | proc_id_connector(task, PROC_EVENT_GID); |
390 | 402 | ||
403 | /* release the old obj and subj refs both */ | ||
404 | put_cred(old); | ||
391 | put_cred(old); | 405 | put_cred(old); |
392 | return 0; | 406 | return 0; |
393 | } | 407 | } |
@@ -408,11 +422,11 @@ void abort_creds(struct cred *new) | |||
408 | EXPORT_SYMBOL(abort_creds); | 422 | EXPORT_SYMBOL(abort_creds); |
409 | 423 | ||
410 | /** | 424 | /** |
411 | * override_creds - Temporarily override the current process's credentials | 425 | * override_creds - Override the current process's subjective credentials |
412 | * @new: The credentials to be assigned | 426 | * @new: The credentials to be assigned |
413 | * | 427 | * |
414 | * Install a set of temporary override credentials on the current process, | 428 | * Install a set of temporary override subjective credentials on the current |
415 | * returning the old set for later reversion. | 429 | * process, returning the old set for later reversion. |
416 | */ | 430 | */ |
417 | const struct cred *override_creds(const struct cred *new) | 431 | const struct cred *override_creds(const struct cred *new) |
418 | { | 432 | { |
@@ -424,11 +438,11 @@ const struct cred *override_creds(const struct cred *new) | |||
424 | EXPORT_SYMBOL(override_creds); | 438 | EXPORT_SYMBOL(override_creds); |
425 | 439 | ||
426 | /** | 440 | /** |
427 | * revert_creds - Revert a temporary credentials override | 441 | * revert_creds - Revert a temporary subjective credentials override |
428 | * @old: The credentials to be restored | 442 | * @old: The credentials to be restored |
429 | * | 443 | * |
430 | * Revert a temporary set of override credentials to an old set, discarding the | 444 | * Revert a temporary set of override subjective credentials to an old set, |
431 | * override set. | 445 | * discarding the override set. |
432 | */ | 446 | */ |
433 | void revert_creds(const struct cred *old) | 447 | void revert_creds(const struct cred *old) |
434 | { | 448 | { |
diff --git a/kernel/fork.c b/kernel/fork.c index 82a7948a664e..af0d0f04585c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -146,6 +146,7 @@ void __put_task_struct(struct task_struct *tsk) | |||
146 | WARN_ON(atomic_read(&tsk->usage)); | 146 | WARN_ON(atomic_read(&tsk->usage)); |
147 | WARN_ON(tsk == current); | 147 | WARN_ON(tsk == current); |
148 | 148 | ||
149 | put_cred(tsk->real_cred); | ||
149 | put_cred(tsk->cred); | 150 | put_cred(tsk->cred); |
150 | delayacct_tsk_free(tsk); | 151 | delayacct_tsk_free(tsk); |
151 | 152 | ||
@@ -961,10 +962,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
961 | DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); | 962 | DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); |
962 | #endif | 963 | #endif |
963 | retval = -EAGAIN; | 964 | retval = -EAGAIN; |
964 | if (atomic_read(&p->cred->user->processes) >= | 965 | if (atomic_read(&p->real_cred->user->processes) >= |
965 | p->signal->rlim[RLIMIT_NPROC].rlim_cur) { | 966 | p->signal->rlim[RLIMIT_NPROC].rlim_cur) { |
966 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && | 967 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && |
967 | p->cred->user != current->nsproxy->user_ns->root_user) | 968 | p->real_cred->user != current->nsproxy->user_ns->root_user) |
968 | goto bad_fork_free; | 969 | goto bad_fork_free; |
969 | } | 970 | } |
970 | 971 | ||
@@ -1278,6 +1279,7 @@ bad_fork_cleanup_put_domain: | |||
1278 | module_put(task_thread_info(p)->exec_domain->module); | 1279 | module_put(task_thread_info(p)->exec_domain->module); |
1279 | bad_fork_cleanup_count: | 1280 | bad_fork_cleanup_count: |
1280 | atomic_dec(&p->cred->user->processes); | 1281 | atomic_dec(&p->cred->user->processes); |
1282 | put_cred(p->real_cred); | ||
1281 | put_cred(p->cred); | 1283 | put_cred(p->cred); |
1282 | bad_fork_free: | 1284 | bad_fork_free: |
1283 | free_task(p); | 1285 | free_task(p); |