diff options
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 213 |
1 files changed, 125 insertions, 88 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 2eb0e471cd40..9b0369c5a223 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* process_keys.c: management of a process's keyrings | 1 | /* process_keys.c: management of a process's keyrings |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -38,10 +38,9 @@ struct key root_user_keyring = { | |||
38 | .serial = 2, | 38 | .serial = 2, |
39 | .type = &key_type_keyring, | 39 | .type = &key_type_keyring, |
40 | .user = &root_key_user, | 40 | .user = &root_key_user, |
41 | .lock = RW_LOCK_UNLOCKED, | ||
42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | 41 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), |
43 | .perm = KEY_USR_ALL, | 42 | .perm = KEY_USR_ALL, |
44 | .flags = KEY_FLAG_INSTANTIATED, | 43 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
45 | .description = "_uid.0", | 44 | .description = "_uid.0", |
46 | #ifdef KEY_DEBUGGING | 45 | #ifdef KEY_DEBUGGING |
47 | .magic = KEY_DEBUG_MAGIC, | 46 | .magic = KEY_DEBUG_MAGIC, |
@@ -54,10 +53,9 @@ struct key root_session_keyring = { | |||
54 | .serial = 1, | 53 | .serial = 1, |
55 | .type = &key_type_keyring, | 54 | .type = &key_type_keyring, |
56 | .user = &root_key_user, | 55 | .user = &root_key_user, |
57 | .lock = RW_LOCK_UNLOCKED, | ||
58 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | 56 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), |
59 | .perm = KEY_USR_ALL, | 57 | .perm = KEY_USR_ALL, |
60 | .flags = KEY_FLAG_INSTANTIATED, | 58 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
61 | .description = "_uid_ses.0", | 59 | .description = "_uid_ses.0", |
62 | #ifdef KEY_DEBUGGING | 60 | #ifdef KEY_DEBUGGING |
63 | .magic = KEY_DEBUG_MAGIC, | 61 | .magic = KEY_DEBUG_MAGIC, |
@@ -167,7 +165,7 @@ int install_thread_keyring(struct task_struct *tsk) | |||
167 | /* | 165 | /* |
168 | * make sure a process keyring is installed | 166 | * make sure a process keyring is installed |
169 | */ | 167 | */ |
170 | static int install_process_keyring(struct task_struct *tsk) | 168 | int install_process_keyring(struct task_struct *tsk) |
171 | { | 169 | { |
172 | unsigned long flags; | 170 | unsigned long flags; |
173 | struct key *keyring; | 171 | struct key *keyring; |
@@ -183,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk) | |||
183 | goto error; | 181 | goto error; |
184 | } | 182 | } |
185 | 183 | ||
186 | /* attach or swap keyrings */ | 184 | /* attach keyring */ |
187 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 185 | spin_lock_irqsave(&tsk->sighand->siglock, flags); |
188 | if (!tsk->signal->process_keyring) { | 186 | if (!tsk->signal->process_keyring) { |
189 | tsk->signal->process_keyring = keyring; | 187 | tsk->signal->process_keyring = keyring; |
@@ -229,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk, | |||
229 | 227 | ||
230 | /* install the keyring */ | 228 | /* install the keyring */ |
231 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 229 | spin_lock_irqsave(&tsk->sighand->siglock, flags); |
232 | old = tsk->signal->session_keyring; | 230 | old = rcu_dereference(tsk->signal->session_keyring); |
233 | tsk->signal->session_keyring = keyring; | 231 | rcu_assign_pointer(tsk->signal->session_keyring, keyring); |
234 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 232 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); |
235 | 233 | ||
236 | ret = 0; | 234 | ret = 0; |
237 | 235 | ||
236 | /* we're using RCU on the pointer */ | ||
237 | synchronize_rcu(); | ||
238 | key_put(old); | 238 | key_put(old); |
239 | error: | 239 | error: |
240 | return ret; | 240 | return ret; |
@@ -247,8 +247,6 @@ static int install_session_keyring(struct task_struct *tsk, | |||
247 | */ | 247 | */ |
248 | int copy_thread_group_keys(struct task_struct *tsk) | 248 | int copy_thread_group_keys(struct task_struct *tsk) |
249 | { | 249 | { |
250 | unsigned long flags; | ||
251 | |||
252 | key_check(current->thread_group->session_keyring); | 250 | key_check(current->thread_group->session_keyring); |
253 | key_check(current->thread_group->process_keyring); | 251 | key_check(current->thread_group->process_keyring); |
254 | 252 | ||
@@ -256,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk) | |||
256 | tsk->signal->process_keyring = NULL; | 254 | tsk->signal->process_keyring = NULL; |
257 | 255 | ||
258 | /* same session keyring */ | 256 | /* same session keyring */ |
259 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 257 | rcu_read_lock(); |
260 | tsk->signal->session_keyring = | 258 | tsk->signal->session_keyring = |
261 | key_get(current->signal->session_keyring); | 259 | key_get(rcu_dereference(current->signal->session_keyring)); |
262 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 260 | rcu_read_unlock(); |
263 | 261 | ||
264 | return 0; | 262 | return 0; |
265 | 263 | ||
@@ -349,9 +347,7 @@ void key_fsuid_changed(struct task_struct *tsk) | |||
349 | /* update the ownership of the thread keyring */ | 347 | /* update the ownership of the thread keyring */ |
350 | if (tsk->thread_keyring) { | 348 | if (tsk->thread_keyring) { |
351 | down_write(&tsk->thread_keyring->sem); | 349 | down_write(&tsk->thread_keyring->sem); |
352 | write_lock(&tsk->thread_keyring->lock); | ||
353 | tsk->thread_keyring->uid = tsk->fsuid; | 350 | tsk->thread_keyring->uid = tsk->fsuid; |
354 | write_unlock(&tsk->thread_keyring->lock); | ||
355 | up_write(&tsk->thread_keyring->sem); | 351 | up_write(&tsk->thread_keyring->sem); |
356 | } | 352 | } |
357 | 353 | ||
@@ -366,9 +362,7 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
366 | /* update the ownership of the thread keyring */ | 362 | /* update the ownership of the thread keyring */ |
367 | if (tsk->thread_keyring) { | 363 | if (tsk->thread_keyring) { |
368 | down_write(&tsk->thread_keyring->sem); | 364 | down_write(&tsk->thread_keyring->sem); |
369 | write_lock(&tsk->thread_keyring->lock); | ||
370 | tsk->thread_keyring->gid = tsk->fsgid; | 365 | tsk->thread_keyring->gid = tsk->fsgid; |
371 | write_unlock(&tsk->thread_keyring->lock); | ||
372 | up_write(&tsk->thread_keyring->sem); | 366 | up_write(&tsk->thread_keyring->sem); |
373 | } | 367 | } |
374 | 368 | ||
@@ -382,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
382 | * - we return -EAGAIN if we didn't find any matching key | 376 | * - we return -EAGAIN if we didn't find any matching key |
383 | * - we return -ENOKEY if we found only negative matching keys | 377 | * - we return -ENOKEY if we found only negative matching keys |
384 | */ | 378 | */ |
385 | struct key *search_process_keyrings_aux(struct key_type *type, | 379 | struct key *search_process_keyrings(struct key_type *type, |
386 | const void *description, | 380 | const void *description, |
387 | key_match_func_t match) | 381 | key_match_func_t match, |
382 | struct task_struct *context) | ||
388 | { | 383 | { |
389 | struct task_struct *tsk = current; | 384 | struct request_key_auth *rka; |
390 | unsigned long flags; | 385 | struct key *key, *ret, *err, *instkey; |
391 | struct key *key, *ret, *err, *tmp; | ||
392 | 386 | ||
393 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 387 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
394 | * searchable, but we failed to find a key or we found a negative key; | 388 | * searchable, but we failed to find a key or we found a negative key; |
@@ -402,9 +396,9 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
402 | err = ERR_PTR(-EAGAIN); | 396 | err = ERR_PTR(-EAGAIN); |
403 | 397 | ||
404 | /* search the thread keyring first */ | 398 | /* search the thread keyring first */ |
405 | if (tsk->thread_keyring) { | 399 | if (context->thread_keyring) { |
406 | key = keyring_search_aux(tsk->thread_keyring, type, | 400 | key = keyring_search_aux(context->thread_keyring, |
407 | description, match); | 401 | context, type, description, match); |
408 | if (!IS_ERR(key)) | 402 | if (!IS_ERR(key)) |
409 | goto found; | 403 | goto found; |
410 | 404 | ||
@@ -422,9 +416,9 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
422 | } | 416 | } |
423 | 417 | ||
424 | /* search the process keyring second */ | 418 | /* search the process keyring second */ |
425 | if (tsk->signal->process_keyring) { | 419 | if (context->signal->process_keyring) { |
426 | key = keyring_search_aux(tsk->signal->process_keyring, | 420 | key = keyring_search_aux(context->signal->process_keyring, |
427 | type, description, match); | 421 | context, type, description, match); |
428 | if (!IS_ERR(key)) | 422 | if (!IS_ERR(key)) |
429 | goto found; | 423 | goto found; |
430 | 424 | ||
@@ -441,52 +435,93 @@ struct key *search_process_keyrings_aux(struct key_type *type, | |||
441 | } | 435 | } |
442 | } | 436 | } |
443 | 437 | ||
444 | /* search the session keyring last */ | 438 | /* search the session keyring */ |
445 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 439 | if (context->signal->session_keyring) { |
440 | rcu_read_lock(); | ||
441 | key = keyring_search_aux( | ||
442 | rcu_dereference(context->signal->session_keyring), | ||
443 | context, type, description, match); | ||
444 | rcu_read_unlock(); | ||
446 | 445 | ||
447 | tmp = tsk->signal->session_keyring; | 446 | if (!IS_ERR(key)) |
448 | if (!tmp) | 447 | goto found; |
449 | tmp = tsk->user->session_keyring; | ||
450 | atomic_inc(&tmp->usage); | ||
451 | 448 | ||
452 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 449 | switch (PTR_ERR(key)) { |
450 | case -EAGAIN: /* no key */ | ||
451 | if (ret) | ||
452 | break; | ||
453 | case -ENOKEY: /* negative key */ | ||
454 | ret = key; | ||
455 | break; | ||
456 | default: | ||
457 | err = key; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | /* if this process has a session keyring and that has an | ||
462 | * instantiation authorisation key in the bottom level, then we | ||
463 | * also search the keyrings of the process mentioned there */ | ||
464 | if (context != current) | ||
465 | goto no_key; | ||
466 | |||
467 | rcu_read_lock(); | ||
468 | instkey = __keyring_search_one( | ||
469 | rcu_dereference(context->signal->session_keyring), | ||
470 | &key_type_request_key_auth, NULL, 0); | ||
471 | rcu_read_unlock(); | ||
472 | |||
473 | if (IS_ERR(instkey)) | ||
474 | goto no_key; | ||
475 | |||
476 | rka = instkey->payload.data; | ||
453 | 477 | ||
454 | key = keyring_search_aux(tmp, type, description, match); | 478 | key = search_process_keyrings(type, description, match, |
455 | key_put(tmp); | 479 | rka->context); |
456 | if (!IS_ERR(key)) | 480 | key_put(instkey); |
457 | goto found; | ||
458 | 481 | ||
459 | switch (PTR_ERR(key)) { | 482 | if (!IS_ERR(key)) |
460 | case -EAGAIN: /* no key */ | 483 | goto found; |
461 | if (ret) | 484 | |
485 | switch (PTR_ERR(key)) { | ||
486 | case -EAGAIN: /* no key */ | ||
487 | if (ret) | ||
488 | break; | ||
489 | case -ENOKEY: /* negative key */ | ||
490 | ret = key; | ||
462 | break; | 491 | break; |
463 | case -ENOKEY: /* negative key */ | 492 | default: |
464 | ret = key; | 493 | err = key; |
465 | break; | 494 | break; |
466 | default: | 495 | } |
467 | err = key; | 496 | } |
468 | break; | 497 | /* or search the user-session keyring */ |
498 | else { | ||
499 | key = keyring_search_aux(context->user->session_keyring, | ||
500 | context, type, description, match); | ||
501 | if (!IS_ERR(key)) | ||
502 | goto found; | ||
503 | |||
504 | switch (PTR_ERR(key)) { | ||
505 | case -EAGAIN: /* no key */ | ||
506 | if (ret) | ||
507 | break; | ||
508 | case -ENOKEY: /* negative key */ | ||
509 | ret = key; | ||
510 | break; | ||
511 | default: | ||
512 | err = key; | ||
513 | break; | ||
514 | } | ||
469 | } | 515 | } |
470 | 516 | ||
517 | |||
518 | no_key: | ||
471 | /* no key - decide on the error we're going to go for */ | 519 | /* no key - decide on the error we're going to go for */ |
472 | key = ret ? ret : err; | 520 | key = ret ? ret : err; |
473 | 521 | ||
474 | found: | 522 | found: |
475 | return key; | 523 | return key; |
476 | 524 | ||
477 | } /* end search_process_keyrings_aux() */ | ||
478 | |||
479 | /*****************************************************************************/ | ||
480 | /* | ||
481 | * search the process keyrings for the first matching key | ||
482 | * - we return -EAGAIN if we didn't find any matching key | ||
483 | * - we return -ENOKEY if we found only negative matching keys | ||
484 | */ | ||
485 | struct key *search_process_keyrings(struct key_type *type, | ||
486 | const char *description) | ||
487 | { | ||
488 | return search_process_keyrings_aux(type, description, type->match); | ||
489 | |||
490 | } /* end search_process_keyrings() */ | 525 | } /* end search_process_keyrings() */ |
491 | 526 | ||
492 | /*****************************************************************************/ | 527 | /*****************************************************************************/ |
@@ -495,72 +530,73 @@ struct key *search_process_keyrings(struct key_type *type, | |||
495 | * - don't create special keyrings unless so requested | 530 | * - don't create special keyrings unless so requested |
496 | * - partially constructed keys aren't found unless requested | 531 | * - partially constructed keys aren't found unless requested |
497 | */ | 532 | */ |
498 | struct key *lookup_user_key(key_serial_t id, int create, int partial, | 533 | struct key *lookup_user_key(struct task_struct *context, key_serial_t id, |
499 | key_perm_t perm) | 534 | int create, int partial, key_perm_t perm) |
500 | { | 535 | { |
501 | struct task_struct *tsk = current; | ||
502 | unsigned long flags; | ||
503 | struct key *key; | 536 | struct key *key; |
504 | int ret; | 537 | int ret; |
505 | 538 | ||
539 | if (!context) | ||
540 | context = current; | ||
541 | |||
506 | key = ERR_PTR(-ENOKEY); | 542 | key = ERR_PTR(-ENOKEY); |
507 | 543 | ||
508 | switch (id) { | 544 | switch (id) { |
509 | case KEY_SPEC_THREAD_KEYRING: | 545 | case KEY_SPEC_THREAD_KEYRING: |
510 | if (!tsk->thread_keyring) { | 546 | if (!context->thread_keyring) { |
511 | if (!create) | 547 | if (!create) |
512 | goto error; | 548 | goto error; |
513 | 549 | ||
514 | ret = install_thread_keyring(tsk); | 550 | ret = install_thread_keyring(context); |
515 | if (ret < 0) { | 551 | if (ret < 0) { |
516 | key = ERR_PTR(ret); | 552 | key = ERR_PTR(ret); |
517 | goto error; | 553 | goto error; |
518 | } | 554 | } |
519 | } | 555 | } |
520 | 556 | ||
521 | key = tsk->thread_keyring; | 557 | key = context->thread_keyring; |
522 | atomic_inc(&key->usage); | 558 | atomic_inc(&key->usage); |
523 | break; | 559 | break; |
524 | 560 | ||
525 | case KEY_SPEC_PROCESS_KEYRING: | 561 | case KEY_SPEC_PROCESS_KEYRING: |
526 | if (!tsk->signal->process_keyring) { | 562 | if (!context->signal->process_keyring) { |
527 | if (!create) | 563 | if (!create) |
528 | goto error; | 564 | goto error; |
529 | 565 | ||
530 | ret = install_process_keyring(tsk); | 566 | ret = install_process_keyring(context); |
531 | if (ret < 0) { | 567 | if (ret < 0) { |
532 | key = ERR_PTR(ret); | 568 | key = ERR_PTR(ret); |
533 | goto error; | 569 | goto error; |
534 | } | 570 | } |
535 | } | 571 | } |
536 | 572 | ||
537 | key = tsk->signal->process_keyring; | 573 | key = context->signal->process_keyring; |
538 | atomic_inc(&key->usage); | 574 | atomic_inc(&key->usage); |
539 | break; | 575 | break; |
540 | 576 | ||
541 | case KEY_SPEC_SESSION_KEYRING: | 577 | case KEY_SPEC_SESSION_KEYRING: |
542 | if (!tsk->signal->session_keyring) { | 578 | if (!context->signal->session_keyring) { |
543 | /* always install a session keyring upon access if one | 579 | /* always install a session keyring upon access if one |
544 | * doesn't exist yet */ | 580 | * doesn't exist yet */ |
545 | ret = install_session_keyring( | 581 | ret = install_session_keyring( |
546 | tsk, tsk->user->session_keyring); | 582 | context, context->user->session_keyring); |
547 | if (ret < 0) | 583 | if (ret < 0) |
548 | goto error; | 584 | goto error; |
549 | } | 585 | } |
550 | 586 | ||
551 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 587 | rcu_read_lock(); |
552 | key = tsk->signal->session_keyring; | 588 | key = rcu_dereference(context->signal->session_keyring); |
553 | atomic_inc(&key->usage); | 589 | atomic_inc(&key->usage); |
554 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 590 | rcu_read_unlock(); |
555 | break; | 591 | break; |
556 | 592 | ||
557 | case KEY_SPEC_USER_KEYRING: | 593 | case KEY_SPEC_USER_KEYRING: |
558 | key = tsk->user->uid_keyring; | 594 | key = context->user->uid_keyring; |
559 | atomic_inc(&key->usage); | 595 | atomic_inc(&key->usage); |
560 | break; | 596 | break; |
561 | 597 | ||
562 | case KEY_SPEC_USER_SESSION_KEYRING: | 598 | case KEY_SPEC_USER_SESSION_KEYRING: |
563 | key = tsk->user->session_keyring; | 599 | key = context->user->session_keyring; |
564 | atomic_inc(&key->usage); | 600 | atomic_inc(&key->usage); |
565 | break; | 601 | break; |
566 | 602 | ||
@@ -580,7 +616,7 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
580 | break; | 616 | break; |
581 | } | 617 | } |
582 | 618 | ||
583 | /* check the status and permissions */ | 619 | /* check the status */ |
584 | if (perm) { | 620 | if (perm) { |
585 | ret = key_validate(key); | 621 | ret = key_validate(key); |
586 | if (ret < 0) | 622 | if (ret < 0) |
@@ -588,11 +624,13 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
588 | } | 624 | } |
589 | 625 | ||
590 | ret = -EIO; | 626 | ret = -EIO; |
591 | if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED)) | 627 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
592 | goto invalid_key; | 628 | goto invalid_key; |
593 | 629 | ||
630 | /* check the permissions */ | ||
594 | ret = -EACCES; | 631 | ret = -EACCES; |
595 | if (!key_permission(key, perm)) | 632 | |
633 | if (!key_task_permission(key, context, perm)) | ||
596 | goto invalid_key; | 634 | goto invalid_key; |
597 | 635 | ||
598 | error: | 636 | error: |
@@ -615,7 +653,6 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
615 | long join_session_keyring(const char *name) | 653 | long join_session_keyring(const char *name) |
616 | { | 654 | { |
617 | struct task_struct *tsk = current; | 655 | struct task_struct *tsk = current; |
618 | unsigned long flags; | ||
619 | struct key *keyring; | 656 | struct key *keyring; |
620 | long ret; | 657 | long ret; |
621 | 658 | ||
@@ -625,9 +662,9 @@ long join_session_keyring(const char *name) | |||
625 | if (ret < 0) | 662 | if (ret < 0) |
626 | goto error; | 663 | goto error; |
627 | 664 | ||
628 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | 665 | rcu_read_lock(); |
629 | ret = tsk->signal->session_keyring->serial; | 666 | ret = rcu_dereference(tsk->signal->session_keyring)->serial; |
630 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | 667 | rcu_read_unlock(); |
631 | goto error; | 668 | goto error; |
632 | } | 669 | } |
633 | 670 | ||