diff options
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 132 |
1 files changed, 64 insertions, 68 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 5d22c0388b32..d65a180f888d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -481,51 +481,6 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
481 | 481 | ||
482 | /*****************************************************************************/ | 482 | /*****************************************************************************/ |
483 | /* | 483 | /* |
484 | * search for an instantiation authorisation key matching a target key | ||
485 | * - the RCU read lock must be held by the caller | ||
486 | * - a target_id of zero specifies any valid token | ||
487 | */ | ||
488 | struct key *keyring_search_instkey(struct key *keyring, | ||
489 | key_serial_t target_id) | ||
490 | { | ||
491 | struct request_key_auth *rka; | ||
492 | struct keyring_list *klist; | ||
493 | struct key *instkey; | ||
494 | int loop; | ||
495 | |||
496 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
497 | if (klist) { | ||
498 | for (loop = 0; loop < klist->nkeys; loop++) { | ||
499 | instkey = klist->keys[loop]; | ||
500 | |||
501 | if (instkey->type != &key_type_request_key_auth) | ||
502 | continue; | ||
503 | |||
504 | rka = instkey->payload.data; | ||
505 | if (target_id && rka->target_key->serial != target_id) | ||
506 | continue; | ||
507 | |||
508 | /* the auth key is revoked during instantiation */ | ||
509 | if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags)) | ||
510 | goto found; | ||
511 | |||
512 | instkey = ERR_PTR(-EKEYREVOKED); | ||
513 | goto error; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | instkey = ERR_PTR(-EACCES); | ||
518 | goto error; | ||
519 | |||
520 | found: | ||
521 | atomic_inc(&instkey->usage); | ||
522 | error: | ||
523 | return instkey; | ||
524 | |||
525 | } /* end keyring_search_instkey() */ | ||
526 | |||
527 | /*****************************************************************************/ | ||
528 | /* | ||
529 | * find a keyring with the specified name | 484 | * find a keyring with the specified name |
530 | * - all named keyrings are searched | 485 | * - all named keyrings are searched |
531 | * - only find keyrings with search permission for the process | 486 | * - only find keyrings with search permission for the process |
@@ -684,15 +639,31 @@ static void keyring_link_rcu_disposal(struct rcu_head *rcu) | |||
684 | 639 | ||
685 | /*****************************************************************************/ | 640 | /*****************************************************************************/ |
686 | /* | 641 | /* |
642 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | ||
643 | * key | ||
644 | */ | ||
645 | static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | ||
646 | { | ||
647 | struct keyring_list *klist = | ||
648 | container_of(rcu, struct keyring_list, rcu); | ||
649 | |||
650 | key_put(klist->keys[klist->delkey]); | ||
651 | kfree(klist); | ||
652 | |||
653 | } /* end keyring_unlink_rcu_disposal() */ | ||
654 | |||
655 | /*****************************************************************************/ | ||
656 | /* | ||
687 | * link a key into to a keyring | 657 | * link a key into to a keyring |
688 | * - must be called with the keyring's semaphore write-locked | 658 | * - must be called with the keyring's semaphore write-locked |
659 | * - discard already extant link to matching key if there is one | ||
689 | */ | 660 | */ |
690 | int __key_link(struct key *keyring, struct key *key) | 661 | int __key_link(struct key *keyring, struct key *key) |
691 | { | 662 | { |
692 | struct keyring_list *klist, *nklist; | 663 | struct keyring_list *klist, *nklist; |
693 | unsigned max; | 664 | unsigned max; |
694 | size_t size; | 665 | size_t size; |
695 | int ret; | 666 | int loop, ret; |
696 | 667 | ||
697 | ret = -EKEYREVOKED; | 668 | ret = -EKEYREVOKED; |
698 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 669 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
@@ -714,6 +685,48 @@ int __key_link(struct key *keyring, struct key *key) | |||
714 | goto error2; | 685 | goto error2; |
715 | } | 686 | } |
716 | 687 | ||
688 | /* see if there's a matching key we can displace */ | ||
689 | klist = keyring->payload.subscriptions; | ||
690 | |||
691 | if (klist && klist->nkeys > 0) { | ||
692 | struct key_type *type = key->type; | ||
693 | |||
694 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | ||
695 | if (klist->keys[loop]->type == type && | ||
696 | strcmp(klist->keys[loop]->description, | ||
697 | key->description) == 0 | ||
698 | ) { | ||
699 | /* found a match - replace with new key */ | ||
700 | size = sizeof(struct key *) * klist->maxkeys; | ||
701 | size += sizeof(*klist); | ||
702 | BUG_ON(size > PAGE_SIZE); | ||
703 | |||
704 | ret = -ENOMEM; | ||
705 | nklist = kmalloc(size, GFP_KERNEL); | ||
706 | if (!nklist) | ||
707 | goto error2; | ||
708 | |||
709 | memcpy(nklist, klist, size); | ||
710 | |||
711 | /* replace matched key */ | ||
712 | atomic_inc(&key->usage); | ||
713 | nklist->keys[loop] = key; | ||
714 | |||
715 | rcu_assign_pointer( | ||
716 | keyring->payload.subscriptions, | ||
717 | nklist); | ||
718 | |||
719 | /* dispose of the old keyring list and the | ||
720 | * displaced key */ | ||
721 | klist->delkey = loop; | ||
722 | call_rcu(&klist->rcu, | ||
723 | keyring_unlink_rcu_disposal); | ||
724 | |||
725 | goto done; | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | |||
717 | /* check that we aren't going to overrun the user's quota */ | 730 | /* check that we aren't going to overrun the user's quota */ |
718 | ret = key_payload_reserve(keyring, | 731 | ret = key_payload_reserve(keyring, |
719 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 732 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
@@ -730,8 +743,6 @@ int __key_link(struct key *keyring, struct key *key) | |||
730 | smp_wmb(); | 743 | smp_wmb(); |
731 | klist->nkeys++; | 744 | klist->nkeys++; |
732 | smp_wmb(); | 745 | smp_wmb(); |
733 | |||
734 | ret = 0; | ||
735 | } | 746 | } |
736 | else { | 747 | else { |
737 | /* grow the key list */ | 748 | /* grow the key list */ |
@@ -769,16 +780,16 @@ int __key_link(struct key *keyring, struct key *key) | |||
769 | /* dispose of the old keyring list */ | 780 | /* dispose of the old keyring list */ |
770 | if (klist) | 781 | if (klist) |
771 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); | 782 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); |
772 | |||
773 | ret = 0; | ||
774 | } | 783 | } |
775 | 784 | ||
776 | error2: | 785 | done: |
786 | ret = 0; | ||
787 | error2: | ||
777 | up_write(&keyring_serialise_link_sem); | 788 | up_write(&keyring_serialise_link_sem); |
778 | error: | 789 | error: |
779 | return ret; | 790 | return ret; |
780 | 791 | ||
781 | error3: | 792 | error3: |
782 | /* undo the quota changes */ | 793 | /* undo the quota changes */ |
783 | key_payload_reserve(keyring, | 794 | key_payload_reserve(keyring, |
784 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 795 | keyring->datalen - KEYQUOTA_LINK_BYTES); |
@@ -809,21 +820,6 @@ EXPORT_SYMBOL(key_link); | |||
809 | 820 | ||
810 | /*****************************************************************************/ | 821 | /*****************************************************************************/ |
811 | /* | 822 | /* |
812 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | ||
813 | * key | ||
814 | */ | ||
815 | static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | ||
816 | { | ||
817 | struct keyring_list *klist = | ||
818 | container_of(rcu, struct keyring_list, rcu); | ||
819 | |||
820 | key_put(klist->keys[klist->delkey]); | ||
821 | kfree(klist); | ||
822 | |||
823 | } /* end keyring_unlink_rcu_disposal() */ | ||
824 | |||
825 | /*****************************************************************************/ | ||
826 | /* | ||
827 | * unlink the first link to a key from a keyring | 823 | * unlink the first link to a key from a keyring |
828 | */ | 824 | */ |
829 | int key_unlink(struct key *keyring, struct key *key) | 825 | int key_unlink(struct key *keyring, struct key *key) |