diff options
| -rw-r--r-- | include/linux/cred.h | 17 | ||||
| -rw-r--r-- | kernel/cred.c | 127 | ||||
| -rw-r--r-- | security/keys/keyctl.c | 11 | ||||
| -rw-r--r-- | security/keys/process_keys.c | 66 | ||||
| -rw-r--r-- | security/keys/request_key.c | 10 |
5 files changed, 50 insertions, 181 deletions
diff --git a/include/linux/cred.h b/include/linux/cred.h index ebbed2ce6637..0142aacb70b7 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
| @@ -77,21 +77,6 @@ extern int in_group_p(kgid_t); | |||
| 77 | extern int in_egroup_p(kgid_t); | 77 | extern int in_egroup_p(kgid_t); |
| 78 | 78 | ||
| 79 | /* | 79 | /* |
| 80 | * The common credentials for a thread group | ||
| 81 | * - shared by CLONE_THREAD | ||
| 82 | */ | ||
| 83 | #ifdef CONFIG_KEYS | ||
| 84 | struct thread_group_cred { | ||
| 85 | atomic_t usage; | ||
| 86 | pid_t tgid; /* thread group process ID */ | ||
| 87 | spinlock_t lock; | ||
| 88 | struct key __rcu *session_keyring; /* keyring inherited over fork */ | ||
| 89 | struct key *process_keyring; /* keyring private to this process */ | ||
| 90 | struct rcu_head rcu; /* RCU deletion hook */ | ||
| 91 | }; | ||
| 92 | #endif | ||
| 93 | |||
| 94 | /* | ||
| 95 | * The security context of a task | 80 | * The security context of a task |
| 96 | * | 81 | * |
| 97 | * The parts of the context break down into two categories: | 82 | * The parts of the context break down into two categories: |
| @@ -139,6 +124,8 @@ struct cred { | |||
| 139 | #ifdef CONFIG_KEYS | 124 | #ifdef CONFIG_KEYS |
| 140 | unsigned char jit_keyring; /* default keyring to attach requested | 125 | unsigned char jit_keyring; /* default keyring to attach requested |
| 141 | * keys to */ | 126 | * keys to */ |
| 127 | struct key __rcu *session_keyring; /* keyring inherited over fork */ | ||
| 128 | struct key *process_keyring; /* keyring private to this process */ | ||
| 142 | struct key *thread_keyring; /* keyring private to this thread */ | 129 | struct key *thread_keyring; /* keyring private to this thread */ |
| 143 | struct key *request_key_auth; /* assumed request_key authority */ | 130 | struct key *request_key_auth; /* assumed request_key authority */ |
| 144 | struct thread_group_cred *tgcred; /* thread-group shared credentials */ | 131 | struct thread_group_cred *tgcred; /* thread-group shared credentials */ |
diff --git a/kernel/cred.c b/kernel/cred.c index de728ac50d82..3f7ad1ec2ae4 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 | ||
| @@ -643,9 +560,6 @@ void __init cred_init(void) | |||
| 643 | */ | 560 | */ |
| 644 | struct cred *prepare_kernel_cred(struct task_struct *daemon) | 561 | struct cred *prepare_kernel_cred(struct task_struct *daemon) |
| 645 | { | 562 | { |
| 646 | #ifdef CONFIG_KEYS | ||
| 647 | struct thread_group_cred *tgcred; | ||
| 648 | #endif | ||
| 649 | const struct cred *old; | 563 | const struct cred *old; |
| 650 | struct cred *new; | 564 | struct cred *new; |
| 651 | 565 | ||
| @@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 653 | if (!new) | 567 | if (!new) |
| 654 | return NULL; | 568 | return NULL; |
| 655 | 569 | ||
| 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); | 570 | kdebug("prepare_kernel_cred() alloc %p", new); |
| 665 | 571 | ||
| 666 | if (daemon) | 572 | if (daemon) |
| @@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 678 | get_group_info(new->group_info); | 584 | get_group_info(new->group_info); |
| 679 | 585 | ||
| 680 | #ifdef CONFIG_KEYS | 586 | #ifdef CONFIG_KEYS |
| 681 | atomic_set(&tgcred->usage, 1); | 587 | new->session_keyring = NULL; |
| 682 | spin_lock_init(&tgcred->lock); | 588 | 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; | 589 | new->thread_keyring = NULL; |
| 590 | new->request_key_auth = NULL; | ||
| 688 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 591 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
| 689 | #endif | 592 | #endif |
| 690 | 593 | ||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index a0d373f76815..65b38417c211 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -1475,7 +1475,8 @@ long keyctl_session_to_parent(void) | |||
| 1475 | goto error_keyring; | 1475 | goto error_keyring; |
| 1476 | newwork = &cred->rcu; | 1476 | newwork = &cred->rcu; |
| 1477 | 1477 | ||
| 1478 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | 1478 | cred->session_keyring = key_ref_to_ptr(keyring_r); |
| 1479 | keyring_r = NULL; | ||
| 1479 | init_task_work(newwork, key_change_session_keyring); | 1480 | init_task_work(newwork, key_change_session_keyring); |
| 1480 | 1481 | ||
| 1481 | me = current; | 1482 | me = current; |
| @@ -1500,7 +1501,7 @@ long keyctl_session_to_parent(void) | |||
| 1500 | mycred = current_cred(); | 1501 | mycred = current_cred(); |
| 1501 | pcred = __task_cred(parent); | 1502 | pcred = __task_cred(parent); |
| 1502 | if (mycred == pcred || | 1503 | if (mycred == pcred || |
| 1503 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) { | 1504 | mycred->session_keyring == pcred->session_keyring) { |
| 1504 | ret = 0; | 1505 | ret = 0; |
| 1505 | goto unlock; | 1506 | goto unlock; |
| 1506 | } | 1507 | } |
| @@ -1516,9 +1517,9 @@ long keyctl_session_to_parent(void) | |||
| 1516 | goto unlock; | 1517 | goto unlock; |
| 1517 | 1518 | ||
| 1518 | /* the keyrings must have the same UID */ | 1519 | /* the keyrings must have the same UID */ |
| 1519 | if ((pcred->tgcred->session_keyring && | 1520 | if ((pcred->session_keyring && |
| 1520 | pcred->tgcred->session_keyring->uid != mycred->euid) || | 1521 | pcred->session_keyring->uid != mycred->euid) || |
| 1521 | mycred->tgcred->session_keyring->uid != mycred->euid) | 1522 | mycred->session_keyring->uid != mycred->euid) |
| 1522 | goto unlock; | 1523 | goto unlock; |
| 1523 | 1524 | ||
| 1524 | /* cancel an already pending keyring replacement */ | 1525 | /* cancel an already pending keyring replacement */ |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 178b8c3b130a..9de5dc598276 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -169,9 +169,8 @@ static int install_thread_keyring(void) | |||
| 169 | int install_process_keyring_to_cred(struct cred *new) | 169 | int install_process_keyring_to_cred(struct cred *new) |
| 170 | { | 170 | { |
| 171 | struct key *keyring; | 171 | struct key *keyring; |
| 172 | int ret; | ||
| 173 | 172 | ||
| 174 | if (new->tgcred->process_keyring) | 173 | if (new->process_keyring) |
| 175 | return -EEXIST; | 174 | return -EEXIST; |
| 176 | 175 | ||
| 177 | keyring = keyring_alloc("_pid", new->uid, new->gid, | 176 | keyring = keyring_alloc("_pid", new->uid, new->gid, |
| @@ -179,17 +178,8 @@ int install_process_keyring_to_cred(struct cred *new) | |||
| 179 | if (IS_ERR(keyring)) | 178 | if (IS_ERR(keyring)) |
| 180 | return PTR_ERR(keyring); | 179 | return PTR_ERR(keyring); |
| 181 | 180 | ||
| 182 | spin_lock_irq(&new->tgcred->lock); | 181 | new->process_keyring = keyring; |
| 183 | if (!new->tgcred->process_keyring) { | 182 | return 0; |
| 184 | new->tgcred->process_keyring = keyring; | ||
| 185 | keyring = NULL; | ||
| 186 | ret = 0; | ||
| 187 | } else { | ||
| 188 | ret = -EEXIST; | ||
| 189 | } | ||
| 190 | spin_unlock_irq(&new->tgcred->lock); | ||
| 191 | key_put(keyring); | ||
| 192 | return ret; | ||
| 193 | } | 183 | } |
| 194 | 184 | ||
| 195 | /* | 185 | /* |
| @@ -230,7 +220,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
| 230 | /* create an empty session keyring */ | 220 | /* create an empty session keyring */ |
| 231 | if (!keyring) { | 221 | if (!keyring) { |
| 232 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 222 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
| 233 | if (cred->tgcred->session_keyring) | 223 | if (cred->session_keyring) |
| 234 | flags = KEY_ALLOC_IN_QUOTA; | 224 | flags = KEY_ALLOC_IN_QUOTA; |
| 235 | 225 | ||
| 236 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, | 226 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, |
| @@ -242,17 +232,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
| 242 | } | 232 | } |
| 243 | 233 | ||
| 244 | /* install the keyring */ | 234 | /* install the keyring */ |
| 245 | spin_lock_irq(&cred->tgcred->lock); | 235 | old = cred->session_keyring; |
| 246 | old = cred->tgcred->session_keyring; | 236 | rcu_assign_pointer(cred->session_keyring, keyring); |
| 247 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); | 237 | |
| 248 | spin_unlock_irq(&cred->tgcred->lock); | 238 | if (old) |
| 249 | |||
| 250 | /* we're using RCU on the pointer, but there's no point synchronising | ||
| 251 | * on it if it didn't previously point to anything */ | ||
| 252 | if (old) { | ||
| 253 | synchronize_rcu(); | ||
| 254 | key_put(old); | 239 | key_put(old); |
| 255 | } | ||
| 256 | 240 | ||
| 257 | return 0; | 241 | return 0; |
| 258 | } | 242 | } |
| @@ -367,9 +351,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
| 367 | } | 351 | } |
| 368 | 352 | ||
| 369 | /* search the process keyring second */ | 353 | /* search the process keyring second */ |
| 370 | if (cred->tgcred->process_keyring) { | 354 | if (cred->process_keyring) { |
| 371 | key_ref = keyring_search_aux( | 355 | key_ref = keyring_search_aux( |
| 372 | make_key_ref(cred->tgcred->process_keyring, 1), | 356 | make_key_ref(cred->process_keyring, 1), |
| 373 | cred, type, description, match, no_state_check); | 357 | cred, type, description, match, no_state_check); |
| 374 | if (!IS_ERR(key_ref)) | 358 | if (!IS_ERR(key_ref)) |
| 375 | goto found; | 359 | goto found; |
| @@ -388,12 +372,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
| 388 | } | 372 | } |
| 389 | 373 | ||
| 390 | /* search the session keyring */ | 374 | /* search the session keyring */ |
| 391 | if (cred->tgcred->session_keyring) { | 375 | if (cred->session_keyring) { |
| 392 | rcu_read_lock(); | 376 | rcu_read_lock(); |
| 393 | key_ref = keyring_search_aux( | 377 | key_ref = keyring_search_aux( |
| 394 | make_key_ref(rcu_dereference( | 378 | make_key_ref(rcu_dereference(cred->session_keyring), 1), |
| 395 | cred->tgcred->session_keyring), | ||
| 396 | 1), | ||
| 397 | cred, type, description, match, no_state_check); | 379 | cred, type, description, match, no_state_check); |
| 398 | rcu_read_unlock(); | 380 | rcu_read_unlock(); |
| 399 | 381 | ||
| @@ -563,7 +545,7 @@ try_again: | |||
| 563 | break; | 545 | break; |
| 564 | 546 | ||
| 565 | case KEY_SPEC_PROCESS_KEYRING: | 547 | case KEY_SPEC_PROCESS_KEYRING: |
| 566 | if (!cred->tgcred->process_keyring) { | 548 | if (!cred->process_keyring) { |
| 567 | if (!(lflags & KEY_LOOKUP_CREATE)) | 549 | if (!(lflags & KEY_LOOKUP_CREATE)) |
| 568 | goto error; | 550 | goto error; |
| 569 | 551 | ||
| @@ -575,13 +557,13 @@ try_again: | |||
| 575 | goto reget_creds; | 557 | goto reget_creds; |
| 576 | } | 558 | } |
| 577 | 559 | ||
| 578 | key = cred->tgcred->process_keyring; | 560 | key = cred->process_keyring; |
| 579 | atomic_inc(&key->usage); | 561 | atomic_inc(&key->usage); |
| 580 | key_ref = make_key_ref(key, 1); | 562 | key_ref = make_key_ref(key, 1); |
| 581 | break; | 563 | break; |
| 582 | 564 | ||
| 583 | case KEY_SPEC_SESSION_KEYRING: | 565 | case KEY_SPEC_SESSION_KEYRING: |
| 584 | if (!cred->tgcred->session_keyring) { | 566 | if (!cred->session_keyring) { |
| 585 | /* always install a session keyring upon access if one | 567 | /* always install a session keyring upon access if one |
| 586 | * doesn't exist yet */ | 568 | * doesn't exist yet */ |
| 587 | ret = install_user_keyrings(); | 569 | ret = install_user_keyrings(); |
| @@ -596,7 +578,7 @@ try_again: | |||
| 596 | if (ret < 0) | 578 | if (ret < 0) |
| 597 | goto error; | 579 | goto error; |
| 598 | goto reget_creds; | 580 | goto reget_creds; |
| 599 | } else if (cred->tgcred->session_keyring == | 581 | } else if (cred->session_keyring == |
| 600 | cred->user->session_keyring && | 582 | cred->user->session_keyring && |
| 601 | lflags & KEY_LOOKUP_CREATE) { | 583 | lflags & KEY_LOOKUP_CREATE) { |
| 602 | ret = join_session_keyring(NULL); | 584 | ret = join_session_keyring(NULL); |
| @@ -606,7 +588,7 @@ try_again: | |||
| 606 | } | 588 | } |
| 607 | 589 | ||
| 608 | rcu_read_lock(); | 590 | rcu_read_lock(); |
| 609 | key = rcu_dereference(cred->tgcred->session_keyring); | 591 | key = rcu_dereference(cred->session_keyring); |
| 610 | atomic_inc(&key->usage); | 592 | atomic_inc(&key->usage); |
| 611 | rcu_read_unlock(); | 593 | rcu_read_unlock(); |
| 612 | key_ref = make_key_ref(key, 1); | 594 | key_ref = make_key_ref(key, 1); |
| @@ -766,12 +748,6 @@ long join_session_keyring(const char *name) | |||
| 766 | struct key *keyring; | 748 | struct key *keyring; |
| 767 | long ret, serial; | 749 | long ret, serial; |
| 768 | 750 | ||
| 769 | /* only permit this if there's a single thread in the thread group - | ||
| 770 | * this avoids us having to adjust the creds on all threads and risking | ||
| 771 | * ENOMEM */ | ||
| 772 | if (!current_is_single_threaded()) | ||
| 773 | return -EMLINK; | ||
| 774 | |||
| 775 | new = prepare_creds(); | 751 | new = prepare_creds(); |
| 776 | if (!new) | 752 | if (!new) |
| 777 | return -ENOMEM; | 753 | return -ENOMEM; |
| @@ -783,7 +759,7 @@ long join_session_keyring(const char *name) | |||
| 783 | if (ret < 0) | 759 | if (ret < 0) |
| 784 | goto error; | 760 | goto error; |
| 785 | 761 | ||
| 786 | serial = new->tgcred->session_keyring->serial; | 762 | serial = new->session_keyring->serial; |
| 787 | ret = commit_creds(new); | 763 | ret = commit_creds(new); |
| 788 | if (ret == 0) | 764 | if (ret == 0) |
| 789 | ret = serial; | 765 | ret = serial; |
| @@ -806,6 +782,9 @@ long join_session_keyring(const char *name) | |||
| 806 | } else if (IS_ERR(keyring)) { | 782 | } else if (IS_ERR(keyring)) { |
| 807 | ret = PTR_ERR(keyring); | 783 | ret = PTR_ERR(keyring); |
| 808 | goto error2; | 784 | goto error2; |
| 785 | } else if (keyring == new->session_keyring) { | ||
| 786 | ret = 0; | ||
| 787 | goto error2; | ||
| 809 | } | 788 | } |
| 810 | 789 | ||
| 811 | /* we've got a keyring - now to install it */ | 790 | /* we've got a keyring - now to install it */ |
| @@ -862,8 +841,7 @@ void key_change_session_keyring(struct callback_head *twork) | |||
| 862 | 841 | ||
| 863 | new->jit_keyring = old->jit_keyring; | 842 | new->jit_keyring = old->jit_keyring; |
| 864 | new->thread_keyring = key_get(old->thread_keyring); | 843 | new->thread_keyring = key_get(old->thread_keyring); |
| 865 | new->tgcred->tgid = old->tgcred->tgid; | 844 | new->process_keyring = key_get(old->process_keyring); |
| 866 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
| 867 | 845 | ||
| 868 | security_transfer_creds(new, old); | 846 | security_transfer_creds(new, old); |
| 869 | 847 | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 000e75017520..275c4f9e4b8c 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -150,12 +150,12 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
| 150 | cred->thread_keyring ? cred->thread_keyring->serial : 0); | 150 | cred->thread_keyring ? cred->thread_keyring->serial : 0); |
| 151 | 151 | ||
| 152 | prkey = 0; | 152 | prkey = 0; |
| 153 | if (cred->tgcred->process_keyring) | 153 | if (cred->process_keyring) |
| 154 | prkey = cred->tgcred->process_keyring->serial; | 154 | prkey = cred->process_keyring->serial; |
| 155 | sprintf(keyring_str[1], "%d", prkey); | 155 | sprintf(keyring_str[1], "%d", prkey); |
| 156 | 156 | ||
| 157 | rcu_read_lock(); | 157 | rcu_read_lock(); |
| 158 | session = rcu_dereference(cred->tgcred->session_keyring); | 158 | session = rcu_dereference(cred->session_keyring); |
| 159 | if (!session) | 159 | if (!session) |
| 160 | session = cred->user->session_keyring; | 160 | session = cred->user->session_keyring; |
| 161 | sskey = session->serial; | 161 | sskey = session->serial; |
| @@ -297,14 +297,14 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
| 297 | break; | 297 | break; |
| 298 | 298 | ||
| 299 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | 299 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
| 300 | dest_keyring = key_get(cred->tgcred->process_keyring); | 300 | dest_keyring = key_get(cred->process_keyring); |
| 301 | if (dest_keyring) | 301 | if (dest_keyring) |
| 302 | break; | 302 | break; |
| 303 | 303 | ||
| 304 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | 304 | case KEY_REQKEY_DEFL_SESSION_KEYRING: |
| 305 | rcu_read_lock(); | 305 | rcu_read_lock(); |
| 306 | dest_keyring = key_get( | 306 | dest_keyring = key_get( |
| 307 | rcu_dereference(cred->tgcred->session_keyring)); | 307 | rcu_dereference(cred->session_keyring)); |
| 308 | rcu_read_unlock(); | 308 | rcu_read_unlock(); |
| 309 | 309 | ||
| 310 | if (dest_keyring) | 310 | if (dest_keyring) |
