aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:26 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:26 -0500
commit3b11a1decef07c19443d24ae926982bc8ec9f4c0 (patch)
treeb6555f0e5b07f4b2badd332a0a900b974920c49d /kernel
parent98870ab0a5a3f1822aee681d2997017e1c87d026 (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.c38
-rw-r--r--kernel/fork.c6
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 */
37struct cred init_cred = { 37struct 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 */
266int copy_creds(struct task_struct *p, unsigned long clone_flags) 271int 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)
408EXPORT_SYMBOL(abort_creds); 422EXPORT_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 */
417const struct cred *override_creds(const struct cred *new) 431const struct cred *override_creds(const struct cred *new)
418{ 432{
@@ -424,11 +438,11 @@ const struct cred *override_creds(const struct cred *new)
424EXPORT_SYMBOL(override_creds); 438EXPORT_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 */
433void revert_creds(const struct cred *old) 447void 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);
1279bad_fork_cleanup_count: 1280bad_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);
1282bad_fork_free: 1284bad_fork_free:
1283 free_task(p); 1285 free_task(p);