diff options
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 141 |
1 files changed, 76 insertions, 65 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 42defae1e161..0cf8a130a267 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -235,7 +235,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
235 | if (IS_ERR(keyring)) | 235 | if (IS_ERR(keyring)) |
236 | return PTR_ERR(keyring); | 236 | return PTR_ERR(keyring); |
237 | } else { | 237 | } else { |
238 | atomic_inc(&keyring->usage); | 238 | __key_get(keyring); |
239 | } | 239 | } |
240 | 240 | ||
241 | /* install the keyring */ | 241 | /* install the keyring */ |
@@ -319,11 +319,7 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
319 | * In the case of a successful return, the possession attribute is set on the | 319 | * In the case of a successful return, the possession attribute is set on the |
320 | * returned key reference. | 320 | * returned key reference. |
321 | */ | 321 | */ |
322 | key_ref_t search_my_process_keyrings(struct key_type *type, | 322 | key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) |
323 | const void *description, | ||
324 | key_match_func_t match, | ||
325 | bool no_state_check, | ||
326 | const struct cred *cred) | ||
327 | { | 323 | { |
328 | key_ref_t key_ref, ret, err; | 324 | key_ref_t key_ref, ret, err; |
329 | 325 | ||
@@ -339,10 +335,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
339 | err = ERR_PTR(-EAGAIN); | 335 | err = ERR_PTR(-EAGAIN); |
340 | 336 | ||
341 | /* search the thread keyring first */ | 337 | /* search the thread keyring first */ |
342 | if (cred->thread_keyring) { | 338 | if (ctx->cred->thread_keyring) { |
343 | key_ref = keyring_search_aux( | 339 | key_ref = keyring_search_aux( |
344 | make_key_ref(cred->thread_keyring, 1), | 340 | make_key_ref(ctx->cred->thread_keyring, 1), ctx); |
345 | cred, type, description, match, no_state_check); | ||
346 | if (!IS_ERR(key_ref)) | 341 | if (!IS_ERR(key_ref)) |
347 | goto found; | 342 | goto found; |
348 | 343 | ||
@@ -358,10 +353,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
358 | } | 353 | } |
359 | 354 | ||
360 | /* search the process keyring second */ | 355 | /* search the process keyring second */ |
361 | if (cred->process_keyring) { | 356 | if (ctx->cred->process_keyring) { |
362 | key_ref = keyring_search_aux( | 357 | key_ref = keyring_search_aux( |
363 | make_key_ref(cred->process_keyring, 1), | 358 | make_key_ref(ctx->cred->process_keyring, 1), ctx); |
364 | cred, type, description, match, no_state_check); | ||
365 | if (!IS_ERR(key_ref)) | 359 | if (!IS_ERR(key_ref)) |
366 | goto found; | 360 | goto found; |
367 | 361 | ||
@@ -379,11 +373,11 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
379 | } | 373 | } |
380 | 374 | ||
381 | /* search the session keyring */ | 375 | /* search the session keyring */ |
382 | if (cred->session_keyring) { | 376 | if (ctx->cred->session_keyring) { |
383 | rcu_read_lock(); | 377 | rcu_read_lock(); |
384 | key_ref = keyring_search_aux( | 378 | key_ref = keyring_search_aux( |
385 | make_key_ref(rcu_dereference(cred->session_keyring), 1), | 379 | make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1), |
386 | cred, type, description, match, no_state_check); | 380 | ctx); |
387 | rcu_read_unlock(); | 381 | rcu_read_unlock(); |
388 | 382 | ||
389 | if (!IS_ERR(key_ref)) | 383 | if (!IS_ERR(key_ref)) |
@@ -402,10 +396,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
402 | } | 396 | } |
403 | } | 397 | } |
404 | /* or search the user-session keyring */ | 398 | /* or search the user-session keyring */ |
405 | else if (cred->user->session_keyring) { | 399 | else if (ctx->cred->user->session_keyring) { |
406 | key_ref = keyring_search_aux( | 400 | key_ref = keyring_search_aux( |
407 | make_key_ref(cred->user->session_keyring, 1), | 401 | make_key_ref(ctx->cred->user->session_keyring, 1), |
408 | cred, type, description, match, no_state_check); | 402 | ctx); |
409 | if (!IS_ERR(key_ref)) | 403 | if (!IS_ERR(key_ref)) |
410 | goto found; | 404 | goto found; |
411 | 405 | ||
@@ -437,18 +431,14 @@ found: | |||
437 | * | 431 | * |
438 | * Return same as search_my_process_keyrings(). | 432 | * Return same as search_my_process_keyrings(). |
439 | */ | 433 | */ |
440 | key_ref_t search_process_keyrings(struct key_type *type, | 434 | key_ref_t search_process_keyrings(struct keyring_search_context *ctx) |
441 | const void *description, | ||
442 | key_match_func_t match, | ||
443 | const struct cred *cred) | ||
444 | { | 435 | { |
445 | struct request_key_auth *rka; | 436 | struct request_key_auth *rka; |
446 | key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; | 437 | key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; |
447 | 438 | ||
448 | might_sleep(); | 439 | might_sleep(); |
449 | 440 | ||
450 | key_ref = search_my_process_keyrings(type, description, match, | 441 | key_ref = search_my_process_keyrings(ctx); |
451 | false, cred); | ||
452 | if (!IS_ERR(key_ref)) | 442 | if (!IS_ERR(key_ref)) |
453 | goto found; | 443 | goto found; |
454 | err = key_ref; | 444 | err = key_ref; |
@@ -457,18 +447,21 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
457 | * search the keyrings of the process mentioned there | 447 | * search the keyrings of the process mentioned there |
458 | * - we don't permit access to request_key auth keys via this method | 448 | * - we don't permit access to request_key auth keys via this method |
459 | */ | 449 | */ |
460 | if (cred->request_key_auth && | 450 | if (ctx->cred->request_key_auth && |
461 | cred == current_cred() && | 451 | ctx->cred == current_cred() && |
462 | type != &key_type_request_key_auth | 452 | ctx->index_key.type != &key_type_request_key_auth |
463 | ) { | 453 | ) { |
454 | const struct cred *cred = ctx->cred; | ||
455 | |||
464 | /* defend against the auth key being revoked */ | 456 | /* defend against the auth key being revoked */ |
465 | down_read(&cred->request_key_auth->sem); | 457 | down_read(&cred->request_key_auth->sem); |
466 | 458 | ||
467 | if (key_validate(cred->request_key_auth) == 0) { | 459 | if (key_validate(ctx->cred->request_key_auth) == 0) { |
468 | rka = cred->request_key_auth->payload.data; | 460 | rka = ctx->cred->request_key_auth->payload.data; |
469 | 461 | ||
470 | key_ref = search_process_keyrings(type, description, | 462 | ctx->cred = rka->cred; |
471 | match, rka->cred); | 463 | key_ref = search_process_keyrings(ctx); |
464 | ctx->cred = cred; | ||
472 | 465 | ||
473 | up_read(&cred->request_key_auth->sem); | 466 | up_read(&cred->request_key_auth->sem); |
474 | 467 | ||
@@ -522,19 +515,23 @@ int lookup_user_key_possessed(const struct key *key, const void *target) | |||
522 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, | 515 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, |
523 | key_perm_t perm) | 516 | key_perm_t perm) |
524 | { | 517 | { |
518 | struct keyring_search_context ctx = { | ||
519 | .match = lookup_user_key_possessed, | ||
520 | .flags = (KEYRING_SEARCH_NO_STATE_CHECK | | ||
521 | KEYRING_SEARCH_LOOKUP_DIRECT), | ||
522 | }; | ||
525 | struct request_key_auth *rka; | 523 | struct request_key_auth *rka; |
526 | const struct cred *cred; | ||
527 | struct key *key; | 524 | struct key *key; |
528 | key_ref_t key_ref, skey_ref; | 525 | key_ref_t key_ref, skey_ref; |
529 | int ret; | 526 | int ret; |
530 | 527 | ||
531 | try_again: | 528 | try_again: |
532 | cred = get_current_cred(); | 529 | ctx.cred = get_current_cred(); |
533 | key_ref = ERR_PTR(-ENOKEY); | 530 | key_ref = ERR_PTR(-ENOKEY); |
534 | 531 | ||
535 | switch (id) { | 532 | switch (id) { |
536 | case KEY_SPEC_THREAD_KEYRING: | 533 | case KEY_SPEC_THREAD_KEYRING: |
537 | if (!cred->thread_keyring) { | 534 | if (!ctx.cred->thread_keyring) { |
538 | if (!(lflags & KEY_LOOKUP_CREATE)) | 535 | if (!(lflags & KEY_LOOKUP_CREATE)) |
539 | goto error; | 536 | goto error; |
540 | 537 | ||
@@ -546,13 +543,13 @@ try_again: | |||
546 | goto reget_creds; | 543 | goto reget_creds; |
547 | } | 544 | } |
548 | 545 | ||
549 | key = cred->thread_keyring; | 546 | key = ctx.cred->thread_keyring; |
550 | atomic_inc(&key->usage); | 547 | __key_get(key); |
551 | key_ref = make_key_ref(key, 1); | 548 | key_ref = make_key_ref(key, 1); |
552 | break; | 549 | break; |
553 | 550 | ||
554 | case KEY_SPEC_PROCESS_KEYRING: | 551 | case KEY_SPEC_PROCESS_KEYRING: |
555 | if (!cred->process_keyring) { | 552 | if (!ctx.cred->process_keyring) { |
556 | if (!(lflags & KEY_LOOKUP_CREATE)) | 553 | if (!(lflags & KEY_LOOKUP_CREATE)) |
557 | goto error; | 554 | goto error; |
558 | 555 | ||
@@ -564,13 +561,13 @@ try_again: | |||
564 | goto reget_creds; | 561 | goto reget_creds; |
565 | } | 562 | } |
566 | 563 | ||
567 | key = cred->process_keyring; | 564 | key = ctx.cred->process_keyring; |
568 | atomic_inc(&key->usage); | 565 | __key_get(key); |
569 | key_ref = make_key_ref(key, 1); | 566 | key_ref = make_key_ref(key, 1); |
570 | break; | 567 | break; |
571 | 568 | ||
572 | case KEY_SPEC_SESSION_KEYRING: | 569 | case KEY_SPEC_SESSION_KEYRING: |
573 | if (!cred->session_keyring) { | 570 | if (!ctx.cred->session_keyring) { |
574 | /* always install a session keyring upon access if one | 571 | /* always install a session keyring upon access if one |
575 | * doesn't exist yet */ | 572 | * doesn't exist yet */ |
576 | ret = install_user_keyrings(); | 573 | ret = install_user_keyrings(); |
@@ -580,13 +577,13 @@ try_again: | |||
580 | ret = join_session_keyring(NULL); | 577 | ret = join_session_keyring(NULL); |
581 | else | 578 | else |
582 | ret = install_session_keyring( | 579 | ret = install_session_keyring( |
583 | cred->user->session_keyring); | 580 | ctx.cred->user->session_keyring); |
584 | 581 | ||
585 | if (ret < 0) | 582 | if (ret < 0) |
586 | goto error; | 583 | goto error; |
587 | goto reget_creds; | 584 | goto reget_creds; |
588 | } else if (cred->session_keyring == | 585 | } else if (ctx.cred->session_keyring == |
589 | cred->user->session_keyring && | 586 | ctx.cred->user->session_keyring && |
590 | lflags & KEY_LOOKUP_CREATE) { | 587 | lflags & KEY_LOOKUP_CREATE) { |
591 | ret = join_session_keyring(NULL); | 588 | ret = join_session_keyring(NULL); |
592 | if (ret < 0) | 589 | if (ret < 0) |
@@ -595,33 +592,33 @@ try_again: | |||
595 | } | 592 | } |
596 | 593 | ||
597 | rcu_read_lock(); | 594 | rcu_read_lock(); |
598 | key = rcu_dereference(cred->session_keyring); | 595 | key = rcu_dereference(ctx.cred->session_keyring); |
599 | atomic_inc(&key->usage); | 596 | __key_get(key); |
600 | rcu_read_unlock(); | 597 | rcu_read_unlock(); |
601 | key_ref = make_key_ref(key, 1); | 598 | key_ref = make_key_ref(key, 1); |
602 | break; | 599 | break; |
603 | 600 | ||
604 | case KEY_SPEC_USER_KEYRING: | 601 | case KEY_SPEC_USER_KEYRING: |
605 | if (!cred->user->uid_keyring) { | 602 | if (!ctx.cred->user->uid_keyring) { |
606 | ret = install_user_keyrings(); | 603 | ret = install_user_keyrings(); |
607 | if (ret < 0) | 604 | if (ret < 0) |
608 | goto error; | 605 | goto error; |
609 | } | 606 | } |
610 | 607 | ||
611 | key = cred->user->uid_keyring; | 608 | key = ctx.cred->user->uid_keyring; |
612 | atomic_inc(&key->usage); | 609 | __key_get(key); |
613 | key_ref = make_key_ref(key, 1); | 610 | key_ref = make_key_ref(key, 1); |
614 | break; | 611 | break; |
615 | 612 | ||
616 | case KEY_SPEC_USER_SESSION_KEYRING: | 613 | case KEY_SPEC_USER_SESSION_KEYRING: |
617 | if (!cred->user->session_keyring) { | 614 | if (!ctx.cred->user->session_keyring) { |
618 | ret = install_user_keyrings(); | 615 | ret = install_user_keyrings(); |
619 | if (ret < 0) | 616 | if (ret < 0) |
620 | goto error; | 617 | goto error; |
621 | } | 618 | } |
622 | 619 | ||
623 | key = cred->user->session_keyring; | 620 | key = ctx.cred->user->session_keyring; |
624 | atomic_inc(&key->usage); | 621 | __key_get(key); |
625 | key_ref = make_key_ref(key, 1); | 622 | key_ref = make_key_ref(key, 1); |
626 | break; | 623 | break; |
627 | 624 | ||
@@ -631,29 +628,29 @@ try_again: | |||
631 | goto error; | 628 | goto error; |
632 | 629 | ||
633 | case KEY_SPEC_REQKEY_AUTH_KEY: | 630 | case KEY_SPEC_REQKEY_AUTH_KEY: |
634 | key = cred->request_key_auth; | 631 | key = ctx.cred->request_key_auth; |
635 | if (!key) | 632 | if (!key) |
636 | goto error; | 633 | goto error; |
637 | 634 | ||
638 | atomic_inc(&key->usage); | 635 | __key_get(key); |
639 | key_ref = make_key_ref(key, 1); | 636 | key_ref = make_key_ref(key, 1); |
640 | break; | 637 | break; |
641 | 638 | ||
642 | case KEY_SPEC_REQUESTOR_KEYRING: | 639 | case KEY_SPEC_REQUESTOR_KEYRING: |
643 | if (!cred->request_key_auth) | 640 | if (!ctx.cred->request_key_auth) |
644 | goto error; | 641 | goto error; |
645 | 642 | ||
646 | down_read(&cred->request_key_auth->sem); | 643 | down_read(&ctx.cred->request_key_auth->sem); |
647 | if (test_bit(KEY_FLAG_REVOKED, | 644 | if (test_bit(KEY_FLAG_REVOKED, |
648 | &cred->request_key_auth->flags)) { | 645 | &ctx.cred->request_key_auth->flags)) { |
649 | key_ref = ERR_PTR(-EKEYREVOKED); | 646 | key_ref = ERR_PTR(-EKEYREVOKED); |
650 | key = NULL; | 647 | key = NULL; |
651 | } else { | 648 | } else { |
652 | rka = cred->request_key_auth->payload.data; | 649 | rka = ctx.cred->request_key_auth->payload.data; |
653 | key = rka->dest_keyring; | 650 | key = rka->dest_keyring; |
654 | atomic_inc(&key->usage); | 651 | __key_get(key); |
655 | } | 652 | } |
656 | up_read(&cred->request_key_auth->sem); | 653 | up_read(&ctx.cred->request_key_auth->sem); |
657 | if (!key) | 654 | if (!key) |
658 | goto error; | 655 | goto error; |
659 | key_ref = make_key_ref(key, 1); | 656 | key_ref = make_key_ref(key, 1); |
@@ -673,9 +670,13 @@ try_again: | |||
673 | key_ref = make_key_ref(key, 0); | 670 | key_ref = make_key_ref(key, 0); |
674 | 671 | ||
675 | /* check to see if we possess the key */ | 672 | /* check to see if we possess the key */ |
676 | skey_ref = search_process_keyrings(key->type, key, | 673 | ctx.index_key.type = key->type; |
677 | lookup_user_key_possessed, | 674 | ctx.index_key.description = key->description; |
678 | cred); | 675 | ctx.index_key.desc_len = strlen(key->description); |
676 | ctx.match_data = key; | ||
677 | kdebug("check possessed"); | ||
678 | skey_ref = search_process_keyrings(&ctx); | ||
679 | kdebug("possessed=%p", skey_ref); | ||
679 | 680 | ||
680 | if (!IS_ERR(skey_ref)) { | 681 | if (!IS_ERR(skey_ref)) { |
681 | key_put(key); | 682 | key_put(key); |
@@ -715,14 +716,14 @@ try_again: | |||
715 | goto invalid_key; | 716 | goto invalid_key; |
716 | 717 | ||
717 | /* check the permissions */ | 718 | /* check the permissions */ |
718 | ret = key_task_permission(key_ref, cred, perm); | 719 | ret = key_task_permission(key_ref, ctx.cred, perm); |
719 | if (ret < 0) | 720 | if (ret < 0) |
720 | goto invalid_key; | 721 | goto invalid_key; |
721 | 722 | ||
722 | key->last_used_at = current_kernel_time().tv_sec; | 723 | key->last_used_at = current_kernel_time().tv_sec; |
723 | 724 | ||
724 | error: | 725 | error: |
725 | put_cred(cred); | 726 | put_cred(ctx.cred); |
726 | return key_ref; | 727 | return key_ref; |
727 | 728 | ||
728 | invalid_key: | 729 | invalid_key: |
@@ -733,7 +734,7 @@ invalid_key: | |||
733 | /* if we attempted to install a keyring, then it may have caused new | 734 | /* if we attempted to install a keyring, then it may have caused new |
734 | * creds to be installed */ | 735 | * creds to be installed */ |
735 | reget_creds: | 736 | reget_creds: |
736 | put_cred(cred); | 737 | put_cred(ctx.cred); |
737 | goto try_again; | 738 | goto try_again; |
738 | } | 739 | } |
739 | 740 | ||
@@ -856,3 +857,13 @@ void key_change_session_keyring(struct callback_head *twork) | |||
856 | 857 | ||
857 | commit_creds(new); | 858 | commit_creds(new); |
858 | } | 859 | } |
860 | |||
861 | /* | ||
862 | * Make sure that root's user and user-session keyrings exist. | ||
863 | */ | ||
864 | static int __init init_root_keyring(void) | ||
865 | { | ||
866 | return install_user_keyrings(); | ||
867 | } | ||
868 | |||
869 | late_initcall(init_root_keyring); | ||