diff options
Diffstat (limited to 'kernel/cred.c')
| -rw-r--r-- | kernel/cred.c | 154 |
1 files changed, 41 insertions, 113 deletions
diff --git a/kernel/cred.c b/kernel/cred.c index 48cea3da6d05..e0573a43c7df 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -30,17 +30,6 @@ | |||
| 30 | static struct kmem_cache *cred_jar; | 30 | static struct kmem_cache *cred_jar; |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * The common credentials for the initial task's thread group | ||
| 34 | */ | ||
| 35 | #ifdef CONFIG_KEYS | ||
| 36 | static struct thread_group_cred init_tgcred = { | ||
| 37 | .usage = ATOMIC_INIT(2), | ||
| 38 | .tgid = 0, | ||
| 39 | .lock = __SPIN_LOCK_UNLOCKED(init_cred.tgcred.lock), | ||
| 40 | }; | ||
| 41 | #endif | ||
| 42 | |||
| 43 | /* | ||
| 44 | * The initial credentials for the initial task | 33 | * The initial credentials for the initial task |
| 45 | */ | 34 | */ |
| 46 | struct cred init_cred = { | 35 | struct cred init_cred = { |
| @@ -65,9 +54,6 @@ struct cred init_cred = { | |||
| 65 | .user = INIT_USER, | 54 | .user = INIT_USER, |
| 66 | .user_ns = &init_user_ns, | 55 | .user_ns = &init_user_ns, |
| 67 | .group_info = &init_groups, | 56 | .group_info = &init_groups, |
| 68 | #ifdef CONFIG_KEYS | ||
| 69 | .tgcred = &init_tgcred, | ||
| 70 | #endif | ||
| 71 | }; | 57 | }; |
| 72 | 58 | ||
| 73 | static inline void set_cred_subscribers(struct cred *cred, int n) | 59 | static inline void set_cred_subscribers(struct cred *cred, int n) |
| @@ -96,36 +82,6 @@ static inline void alter_cred_subscribers(const struct cred *_cred, int n) | |||
| 96 | } | 82 | } |
| 97 | 83 | ||
| 98 | /* | 84 | /* |
| 99 | * Dispose of the shared task group credentials | ||
| 100 | */ | ||
| 101 | #ifdef CONFIG_KEYS | ||
| 102 | static void release_tgcred_rcu(struct rcu_head *rcu) | ||
| 103 | { | ||
| 104 | struct thread_group_cred *tgcred = | ||
| 105 | container_of(rcu, struct thread_group_cred, rcu); | ||
| 106 | |||
| 107 | BUG_ON(atomic_read(&tgcred->usage) != 0); | ||
| 108 | |||
| 109 | key_put(tgcred->session_keyring); | ||
| 110 | key_put(tgcred->process_keyring); | ||
| 111 | kfree(tgcred); | ||
| 112 | } | ||
| 113 | #endif | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Release a set of thread group credentials. | ||
| 117 | */ | ||
| 118 | static void release_tgcred(struct cred *cred) | ||
| 119 | { | ||
| 120 | #ifdef CONFIG_KEYS | ||
| 121 | struct thread_group_cred *tgcred = cred->tgcred; | ||
| 122 | |||
| 123 | if (atomic_dec_and_test(&tgcred->usage)) | ||
| 124 | call_rcu(&tgcred->rcu, release_tgcred_rcu); | ||
| 125 | #endif | ||
| 126 | } | ||
| 127 | |||
| 128 | /* | ||
| 129 | * The RCU callback to actually dispose of a set of credentials | 85 | * The RCU callback to actually dispose of a set of credentials |
| 130 | */ | 86 | */ |
| 131 | static void put_cred_rcu(struct rcu_head *rcu) | 87 | static void put_cred_rcu(struct rcu_head *rcu) |
| @@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
| 150 | #endif | 106 | #endif |
| 151 | 107 | ||
| 152 | security_cred_free(cred); | 108 | security_cred_free(cred); |
| 109 | key_put(cred->session_keyring); | ||
| 110 | key_put(cred->process_keyring); | ||
| 153 | key_put(cred->thread_keyring); | 111 | key_put(cred->thread_keyring); |
| 154 | key_put(cred->request_key_auth); | 112 | key_put(cred->request_key_auth); |
| 155 | release_tgcred(cred); | ||
| 156 | if (cred->group_info) | 113 | if (cred->group_info) |
| 157 | put_group_info(cred->group_info); | 114 | put_group_info(cred->group_info); |
| 158 | free_uid(cred->user); | 115 | free_uid(cred->user); |
| @@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void) | |||
| 246 | if (!new) | 203 | if (!new) |
| 247 | return NULL; | 204 | return NULL; |
| 248 | 205 | ||
| 249 | #ifdef CONFIG_KEYS | ||
| 250 | new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); | ||
| 251 | if (!new->tgcred) { | ||
| 252 | kmem_cache_free(cred_jar, new); | ||
| 253 | return NULL; | ||
| 254 | } | ||
| 255 | atomic_set(&new->tgcred->usage, 1); | ||
| 256 | #endif | ||
| 257 | |||
| 258 | atomic_set(&new->usage, 1); | 206 | atomic_set(&new->usage, 1); |
| 259 | #ifdef CONFIG_DEBUG_CREDENTIALS | 207 | #ifdef CONFIG_DEBUG_CREDENTIALS |
| 260 | new->magic = CRED_MAGIC; | 208 | new->magic = CRED_MAGIC; |
| @@ -308,9 +256,10 @@ struct cred *prepare_creds(void) | |||
| 308 | get_user_ns(new->user_ns); | 256 | get_user_ns(new->user_ns); |
| 309 | 257 | ||
| 310 | #ifdef CONFIG_KEYS | 258 | #ifdef CONFIG_KEYS |
| 259 | key_get(new->session_keyring); | ||
| 260 | key_get(new->process_keyring); | ||
| 311 | key_get(new->thread_keyring); | 261 | key_get(new->thread_keyring); |
| 312 | key_get(new->request_key_auth); | 262 | key_get(new->request_key_auth); |
| 313 | atomic_inc(&new->tgcred->usage); | ||
| 314 | #endif | 263 | #endif |
| 315 | 264 | ||
| 316 | #ifdef CONFIG_SECURITY | 265 | #ifdef CONFIG_SECURITY |
| @@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds); | |||
| 334 | */ | 283 | */ |
| 335 | struct cred *prepare_exec_creds(void) | 284 | struct cred *prepare_exec_creds(void) |
| 336 | { | 285 | { |
| 337 | struct thread_group_cred *tgcred = NULL; | ||
| 338 | struct cred *new; | 286 | struct cred *new; |
| 339 | 287 | ||
| 340 | #ifdef CONFIG_KEYS | ||
| 341 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
| 342 | if (!tgcred) | ||
| 343 | return NULL; | ||
| 344 | #endif | ||
| 345 | |||
| 346 | new = prepare_creds(); | 288 | new = prepare_creds(); |
| 347 | if (!new) { | 289 | if (!new) |
| 348 | kfree(tgcred); | ||
| 349 | return new; | 290 | return new; |
| 350 | } | ||
| 351 | 291 | ||
| 352 | #ifdef CONFIG_KEYS | 292 | #ifdef CONFIG_KEYS |
| 353 | /* newly exec'd tasks don't get a thread keyring */ | 293 | /* newly exec'd tasks don't get a thread keyring */ |
| 354 | key_put(new->thread_keyring); | 294 | key_put(new->thread_keyring); |
| 355 | new->thread_keyring = NULL; | 295 | new->thread_keyring = NULL; |
| 356 | 296 | ||
| 357 | /* create a new per-thread-group creds for all this set of threads to | ||
| 358 | * share */ | ||
| 359 | memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred)); | ||
| 360 | |||
| 361 | atomic_set(&tgcred->usage, 1); | ||
| 362 | spin_lock_init(&tgcred->lock); | ||
| 363 | |||
| 364 | /* inherit the session keyring; new process keyring */ | 297 | /* inherit the session keyring; new process keyring */ |
| 365 | key_get(tgcred->session_keyring); | 298 | key_put(new->process_keyring); |
| 366 | tgcred->process_keyring = NULL; | 299 | new->process_keyring = NULL; |
| 367 | |||
| 368 | release_tgcred(new); | ||
| 369 | new->tgcred = tgcred; | ||
| 370 | #endif | 300 | #endif |
| 371 | 301 | ||
| 372 | return new; | 302 | return new; |
| @@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void) | |||
| 383 | */ | 313 | */ |
| 384 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | 314 | int copy_creds(struct task_struct *p, unsigned long clone_flags) |
| 385 | { | 315 | { |
| 386 | #ifdef CONFIG_KEYS | ||
| 387 | struct thread_group_cred *tgcred; | ||
| 388 | #endif | ||
| 389 | struct cred *new; | 316 | struct cred *new; |
| 390 | int ret; | 317 | int ret; |
| 391 | 318 | ||
| @@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 425 | install_thread_keyring_to_cred(new); | 352 | install_thread_keyring_to_cred(new); |
| 426 | } | 353 | } |
| 427 | 354 | ||
| 428 | /* we share the process and session keyrings between all the threads in | 355 | /* The process keyring is only shared between the threads in a process; |
| 429 | * a process - this is slightly icky as we violate COW credentials a | 356 | * anything outside of those threads doesn't inherit. |
| 430 | * bit */ | 357 | */ |
| 431 | if (!(clone_flags & CLONE_THREAD)) { | 358 | if (!(clone_flags & CLONE_THREAD)) { |
| 432 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | 359 | key_put(new->process_keyring); |
| 433 | if (!tgcred) { | 360 | new->process_keyring = NULL; |
| 434 | ret = -ENOMEM; | ||
| 435 | goto error_put; | ||
| 436 | } | ||
| 437 | atomic_set(&tgcred->usage, 1); | ||
| 438 | spin_lock_init(&tgcred->lock); | ||
| 439 | tgcred->process_keyring = NULL; | ||
| 440 | tgcred->session_keyring = key_get(new->tgcred->session_keyring); | ||
| 441 | |||
| 442 | release_tgcred(new); | ||
| 443 | new->tgcred = tgcred; | ||
| 444 | } | 361 | } |
| 445 | #endif | 362 | #endif |
| 446 | 363 | ||
| @@ -455,6 +372,31 @@ error_put: | |||
| 455 | return ret; | 372 | return ret; |
| 456 | } | 373 | } |
| 457 | 374 | ||
| 375 | static bool cred_cap_issubset(const struct cred *set, const struct cred *subset) | ||
| 376 | { | ||
| 377 | const struct user_namespace *set_ns = set->user_ns; | ||
| 378 | const struct user_namespace *subset_ns = subset->user_ns; | ||
| 379 | |||
| 380 | /* If the two credentials are in the same user namespace see if | ||
| 381 | * the capabilities of subset are a subset of set. | ||
| 382 | */ | ||
| 383 | if (set_ns == subset_ns) | ||
| 384 | return cap_issubset(subset->cap_permitted, set->cap_permitted); | ||
| 385 | |||
| 386 | /* The credentials are in a different user namespaces | ||
| 387 | * therefore one is a subset of the other only if a set is an | ||
| 388 | * ancestor of subset and set->euid is owner of subset or one | ||
| 389 | * of subsets ancestors. | ||
| 390 | */ | ||
| 391 | for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) { | ||
| 392 | if ((set_ns == subset_ns->parent) && | ||
| 393 | uid_eq(subset_ns->owner, set->euid)) | ||
| 394 | return true; | ||
| 395 | } | ||
| 396 | |||
| 397 | return false; | ||
| 398 | } | ||
| 399 | |||
| 458 | /** | 400 | /** |
| 459 | * commit_creds - Install new credentials upon the current task | 401 | * commit_creds - Install new credentials upon the current task |
| 460 | * @new: The credentials to be assigned | 402 | * @new: The credentials to be assigned |
| @@ -493,7 +435,7 @@ int commit_creds(struct cred *new) | |||
| 493 | !gid_eq(old->egid, new->egid) || | 435 | !gid_eq(old->egid, new->egid) || |
| 494 | !uid_eq(old->fsuid, new->fsuid) || | 436 | !uid_eq(old->fsuid, new->fsuid) || |
| 495 | !gid_eq(old->fsgid, new->fsgid) || | 437 | !gid_eq(old->fsgid, new->fsgid) || |
| 496 | !cap_issubset(new->cap_permitted, old->cap_permitted)) { | 438 | !cred_cap_issubset(old, new)) { |
| 497 | if (task->mm) | 439 | if (task->mm) |
| 498 | set_dumpable(task->mm, suid_dumpable); | 440 | set_dumpable(task->mm, suid_dumpable); |
| 499 | task->pdeath_signal = 0; | 441 | task->pdeath_signal = 0; |
| @@ -643,9 +585,6 @@ void __init cred_init(void) | |||
| 643 | */ | 585 | */ |
| 644 | struct cred *prepare_kernel_cred(struct task_struct *daemon) | 586 | struct cred *prepare_kernel_cred(struct task_struct *daemon) |
| 645 | { | 587 | { |
| 646 | #ifdef CONFIG_KEYS | ||
| 647 | struct thread_group_cred *tgcred; | ||
| 648 | #endif | ||
| 649 | const struct cred *old; | 588 | const struct cred *old; |
| 650 | struct cred *new; | 589 | struct cred *new; |
| 651 | 590 | ||
| @@ -653,14 +592,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 653 | if (!new) | 592 | if (!new) |
| 654 | return NULL; | 593 | return NULL; |
| 655 | 594 | ||
| 656 | #ifdef CONFIG_KEYS | ||
| 657 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
| 658 | if (!tgcred) { | ||
| 659 | kmem_cache_free(cred_jar, new); | ||
| 660 | return NULL; | ||
| 661 | } | ||
| 662 | #endif | ||
| 663 | |||
| 664 | kdebug("prepare_kernel_cred() alloc %p", new); | 595 | kdebug("prepare_kernel_cred() alloc %p", new); |
| 665 | 596 | ||
| 666 | if (daemon) | 597 | if (daemon) |
| @@ -678,13 +609,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 678 | get_group_info(new->group_info); | 609 | get_group_info(new->group_info); |
| 679 | 610 | ||
| 680 | #ifdef CONFIG_KEYS | 611 | #ifdef CONFIG_KEYS |
| 681 | atomic_set(&tgcred->usage, 1); | 612 | new->session_keyring = NULL; |
| 682 | spin_lock_init(&tgcred->lock); | 613 | new->process_keyring = NULL; |
| 683 | tgcred->process_keyring = NULL; | ||
| 684 | tgcred->session_keyring = NULL; | ||
| 685 | new->tgcred = tgcred; | ||
| 686 | new->request_key_auth = NULL; | ||
| 687 | new->thread_keyring = NULL; | 614 | new->thread_keyring = NULL; |
| 615 | new->request_key_auth = NULL; | ||
| 688 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 616 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
| 689 | #endif | 617 | #endif |
| 690 | 618 | ||
