diff options
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 273 |
1 files changed, 160 insertions, 113 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 1e4b0037935c..ef03a82a0135 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/seq_file.h> | 17 | #include <linux/seq_file.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <keys/keyring-type.h> | 19 | #include <keys/keyring-type.h> |
20 | #include <asm/uaccess.h> | 20 | #include <linux/uaccess.h> |
21 | #include "internal.h" | 21 | #include "internal.h" |
22 | 22 | ||
23 | #define rcu_dereference_locked_keyring(keyring) \ | 23 | #define rcu_dereference_locked_keyring(keyring) \ |
@@ -44,7 +44,7 @@ static inline unsigned keyring_hash(const char *desc) | |||
44 | unsigned bucket = 0; | 44 | unsigned bucket = 0; |
45 | 45 | ||
46 | for (; *desc; desc++) | 46 | for (; *desc; desc++) |
47 | bucket += (unsigned char) *desc; | 47 | bucket += (unsigned char)*desc; |
48 | 48 | ||
49 | return bucket & (KEYRING_NAME_HASH_SIZE - 1); | 49 | return bucket & (KEYRING_NAME_HASH_SIZE - 1); |
50 | } | 50 | } |
@@ -175,12 +175,10 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) | |||
175 | { | 175 | { |
176 | struct keyring_list *klist; | 176 | struct keyring_list *klist; |
177 | 177 | ||
178 | if (keyring->description) { | 178 | if (keyring->description) |
179 | seq_puts(m, keyring->description); | 179 | seq_puts(m, keyring->description); |
180 | } | 180 | else |
181 | else { | ||
182 | seq_puts(m, "[anon]"); | 181 | seq_puts(m, "[anon]"); |
183 | } | ||
184 | 182 | ||
185 | rcu_read_lock(); | 183 | rcu_read_lock(); |
186 | klist = rcu_dereference(keyring->payload.subscriptions); | 184 | klist = rcu_dereference(keyring->payload.subscriptions); |
@@ -241,7 +239,7 @@ static long keyring_read(const struct key *keyring, | |||
241 | ret = qty; | 239 | ret = qty; |
242 | } | 240 | } |
243 | 241 | ||
244 | error: | 242 | error: |
245 | return ret; | 243 | return ret; |
246 | 244 | ||
247 | } /* end keyring_read() */ | 245 | } /* end keyring_read() */ |
@@ -310,7 +308,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
310 | key_check(keyring); | 308 | key_check(keyring); |
311 | 309 | ||
312 | /* top keyring must have search permission to begin the search */ | 310 | /* top keyring must have search permission to begin the search */ |
313 | err = key_task_permission(keyring_ref, cred, KEY_SEARCH); | 311 | err = key_task_permission(keyring_ref, cred, KEY_SEARCH); |
314 | if (err < 0) { | 312 | if (err < 0) { |
315 | key_ref = ERR_PTR(err); | 313 | key_ref = ERR_PTR(err); |
316 | goto error; | 314 | goto error; |
@@ -512,7 +510,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
512 | rcu_read_unlock(); | 510 | rcu_read_unlock(); |
513 | return ERR_PTR(-ENOKEY); | 511 | return ERR_PTR(-ENOKEY); |
514 | 512 | ||
515 | found: | 513 | found: |
516 | atomic_inc(&key->usage); | 514 | atomic_inc(&key->usage); |
517 | rcu_read_unlock(); | 515 | rcu_read_unlock(); |
518 | return make_key_ref(key, possessed); | 516 | return make_key_ref(key, possessed); |
@@ -602,7 +600,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
602 | sp = 0; | 600 | sp = 0; |
603 | 601 | ||
604 | /* start processing a new keyring */ | 602 | /* start processing a new keyring */ |
605 | descend: | 603 | descend: |
606 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) | 604 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) |
607 | goto not_this_keyring; | 605 | goto not_this_keyring; |
608 | 606 | ||
@@ -611,7 +609,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
611 | goto not_this_keyring; | 609 | goto not_this_keyring; |
612 | kix = 0; | 610 | kix = 0; |
613 | 611 | ||
614 | ascend: | 612 | ascend: |
615 | /* iterate through the remaining keys in this keyring */ | 613 | /* iterate through the remaining keys in this keyring */ |
616 | for (; kix < keylist->nkeys; kix++) { | 614 | for (; kix < keylist->nkeys; kix++) { |
617 | key = keylist->keys[kix]; | 615 | key = keylist->keys[kix]; |
@@ -637,7 +635,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
637 | 635 | ||
638 | /* the keyring we're looking at was disqualified or didn't contain a | 636 | /* the keyring we're looking at was disqualified or didn't contain a |
639 | * matching key */ | 637 | * matching key */ |
640 | not_this_keyring: | 638 | not_this_keyring: |
641 | if (sp > 0) { | 639 | if (sp > 0) { |
642 | /* resume the checking of a keyring higher up in the tree */ | 640 | /* resume the checking of a keyring higher up in the tree */ |
643 | sp--; | 641 | sp--; |
@@ -648,34 +646,20 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
648 | 646 | ||
649 | ret = 0; /* no cycles detected */ | 647 | ret = 0; /* no cycles detected */ |
650 | 648 | ||
651 | error: | 649 | error: |
652 | rcu_read_unlock(); | 650 | rcu_read_unlock(); |
653 | return ret; | 651 | return ret; |
654 | 652 | ||
655 | too_deep: | 653 | too_deep: |
656 | ret = -ELOOP; | 654 | ret = -ELOOP; |
657 | goto error; | 655 | goto error; |
658 | 656 | ||
659 | cycle_detected: | 657 | cycle_detected: |
660 | ret = -EDEADLK; | 658 | ret = -EDEADLK; |
661 | goto error; | 659 | goto error; |
662 | 660 | ||
663 | } /* end keyring_detect_cycle() */ | 661 | } /* end keyring_detect_cycle() */ |
664 | 662 | ||
665 | /*****************************************************************************/ | ||
666 | /* | ||
667 | * dispose of a keyring list after the RCU grace period | ||
668 | */ | ||
669 | static void keyring_link_rcu_disposal(struct rcu_head *rcu) | ||
670 | { | ||
671 | struct keyring_list *klist = | ||
672 | container_of(rcu, struct keyring_list, rcu); | ||
673 | |||
674 | kfree(klist); | ||
675 | |||
676 | } /* end keyring_link_rcu_disposal() */ | ||
677 | |||
678 | /*****************************************************************************/ | ||
679 | /* | 663 | /* |
680 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | 664 | * dispose of a keyring list after the RCU grace period, freeing the unlinked |
681 | * key | 665 | * key |
@@ -685,55 +669,51 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
685 | struct keyring_list *klist = | 669 | struct keyring_list *klist = |
686 | container_of(rcu, struct keyring_list, rcu); | 670 | container_of(rcu, struct keyring_list, rcu); |
687 | 671 | ||
688 | key_put(klist->keys[klist->delkey]); | 672 | if (klist->delkey != USHORT_MAX) |
673 | key_put(klist->keys[klist->delkey]); | ||
689 | kfree(klist); | 674 | kfree(klist); |
675 | } | ||
690 | 676 | ||
691 | } /* end keyring_unlink_rcu_disposal() */ | ||
692 | |||
693 | /*****************************************************************************/ | ||
694 | /* | 677 | /* |
695 | * link a key into to a keyring | 678 | * preallocate memory so that a key can be linked into to a keyring |
696 | * - must be called with the keyring's semaphore write-locked | ||
697 | * - discard already extant link to matching key if there is one | ||
698 | */ | 679 | */ |
699 | int __key_link(struct key *keyring, struct key *key) | 680 | int __key_link_begin(struct key *keyring, const struct key_type *type, |
681 | const char *description, | ||
682 | struct keyring_list **_prealloc) | ||
683 | __acquires(&keyring->sem) | ||
700 | { | 684 | { |
701 | struct keyring_list *klist, *nklist; | 685 | struct keyring_list *klist, *nklist; |
702 | unsigned max; | 686 | unsigned max; |
703 | size_t size; | 687 | size_t size; |
704 | int loop, ret; | 688 | int loop, ret; |
705 | 689 | ||
706 | ret = -EKEYREVOKED; | 690 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
707 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | ||
708 | goto error; | ||
709 | 691 | ||
710 | ret = -ENOTDIR; | ||
711 | if (keyring->type != &key_type_keyring) | 692 | if (keyring->type != &key_type_keyring) |
712 | goto error; | 693 | return -ENOTDIR; |
713 | 694 | ||
714 | /* serialise link/link calls to prevent parallel calls causing a | 695 | down_write(&keyring->sem); |
715 | * cycle when applied to two keyring in opposite orders */ | ||
716 | down_write(&keyring_serialise_link_sem); | ||
717 | 696 | ||
718 | /* check that we aren't going to create a cycle adding one keyring to | 697 | ret = -EKEYREVOKED; |
719 | * another */ | 698 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
720 | if (key->type == &key_type_keyring) { | 699 | goto error_krsem; |
721 | ret = keyring_detect_cycle(keyring, key); | 700 | |
722 | if (ret < 0) | 701 | /* serialise link/link calls to prevent parallel calls causing a cycle |
723 | goto error2; | 702 | * when linking two keyring in opposite orders */ |
724 | } | 703 | if (type == &key_type_keyring) |
704 | down_write(&keyring_serialise_link_sem); | ||
725 | 705 | ||
726 | /* see if there's a matching key we can displace */ | ||
727 | klist = rcu_dereference_locked_keyring(keyring); | 706 | klist = rcu_dereference_locked_keyring(keyring); |
728 | if (klist && klist->nkeys > 0) { | ||
729 | struct key_type *type = key->type; | ||
730 | 707 | ||
708 | /* see if there's a matching key we can displace */ | ||
709 | if (klist && klist->nkeys > 0) { | ||
731 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 710 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
732 | if (klist->keys[loop]->type == type && | 711 | if (klist->keys[loop]->type == type && |
733 | strcmp(klist->keys[loop]->description, | 712 | strcmp(klist->keys[loop]->description, |
734 | key->description) == 0 | 713 | description) == 0 |
735 | ) { | 714 | ) { |
736 | /* found a match - replace with new key */ | 715 | /* found a match - we'll replace this one with |
716 | * the new key */ | ||
737 | size = sizeof(struct key *) * klist->maxkeys; | 717 | size = sizeof(struct key *) * klist->maxkeys; |
738 | size += sizeof(*klist); | 718 | size += sizeof(*klist); |
739 | BUG_ON(size > PAGE_SIZE); | 719 | BUG_ON(size > PAGE_SIZE); |
@@ -741,22 +721,10 @@ int __key_link(struct key *keyring, struct key *key) | |||
741 | ret = -ENOMEM; | 721 | ret = -ENOMEM; |
742 | nklist = kmemdup(klist, size, GFP_KERNEL); | 722 | nklist = kmemdup(klist, size, GFP_KERNEL); |
743 | if (!nklist) | 723 | if (!nklist) |
744 | goto error2; | 724 | goto error_sem; |
745 | |||
746 | /* replace matched key */ | ||
747 | atomic_inc(&key->usage); | ||
748 | nklist->keys[loop] = key; | ||
749 | |||
750 | rcu_assign_pointer( | ||
751 | keyring->payload.subscriptions, | ||
752 | nklist); | ||
753 | |||
754 | /* dispose of the old keyring list and the | ||
755 | * displaced key */ | ||
756 | klist->delkey = loop; | ||
757 | call_rcu(&klist->rcu, | ||
758 | keyring_unlink_rcu_disposal); | ||
759 | 725 | ||
726 | /* note replacement slot */ | ||
727 | klist->delkey = nklist->delkey = loop; | ||
760 | goto done; | 728 | goto done; |
761 | } | 729 | } |
762 | } | 730 | } |
@@ -766,88 +734,167 @@ int __key_link(struct key *keyring, struct key *key) | |||
766 | ret = key_payload_reserve(keyring, | 734 | ret = key_payload_reserve(keyring, |
767 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 735 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
768 | if (ret < 0) | 736 | if (ret < 0) |
769 | goto error2; | 737 | goto error_sem; |
770 | 738 | ||
771 | if (klist && klist->nkeys < klist->maxkeys) { | 739 | if (klist && klist->nkeys < klist->maxkeys) { |
772 | /* there's sufficient slack space to add directly */ | 740 | /* there's sufficient slack space to append directly */ |
773 | atomic_inc(&key->usage); | 741 | nklist = NULL; |
774 | 742 | } else { | |
775 | klist->keys[klist->nkeys] = key; | ||
776 | smp_wmb(); | ||
777 | klist->nkeys++; | ||
778 | smp_wmb(); | ||
779 | } | ||
780 | else { | ||
781 | /* grow the key list */ | 743 | /* grow the key list */ |
782 | max = 4; | 744 | max = 4; |
783 | if (klist) | 745 | if (klist) |
784 | max += klist->maxkeys; | 746 | max += klist->maxkeys; |
785 | 747 | ||
786 | ret = -ENFILE; | 748 | ret = -ENFILE; |
787 | if (max > 65535) | 749 | if (max > USHORT_MAX - 1) |
788 | goto error3; | 750 | goto error_quota; |
789 | size = sizeof(*klist) + sizeof(struct key *) * max; | 751 | size = sizeof(*klist) + sizeof(struct key *) * max; |
790 | if (size > PAGE_SIZE) | 752 | if (size > PAGE_SIZE) |
791 | goto error3; | 753 | goto error_quota; |
792 | 754 | ||
793 | ret = -ENOMEM; | 755 | ret = -ENOMEM; |
794 | nklist = kmalloc(size, GFP_KERNEL); | 756 | nklist = kmalloc(size, GFP_KERNEL); |
795 | if (!nklist) | 757 | if (!nklist) |
796 | goto error3; | 758 | goto error_quota; |
797 | nklist->maxkeys = max; | ||
798 | nklist->nkeys = 0; | ||
799 | 759 | ||
760 | nklist->maxkeys = max; | ||
800 | if (klist) { | 761 | if (klist) { |
801 | nklist->nkeys = klist->nkeys; | 762 | memcpy(nklist->keys, klist->keys, |
802 | memcpy(nklist->keys, | ||
803 | klist->keys, | ||
804 | sizeof(struct key *) * klist->nkeys); | 763 | sizeof(struct key *) * klist->nkeys); |
764 | nklist->delkey = klist->nkeys; | ||
765 | nklist->nkeys = klist->nkeys + 1; | ||
766 | klist->delkey = USHORT_MAX; | ||
767 | } else { | ||
768 | nklist->nkeys = 1; | ||
769 | nklist->delkey = 0; | ||
805 | } | 770 | } |
806 | 771 | ||
807 | /* add the key into the new space */ | 772 | /* add the key into the new space */ |
808 | atomic_inc(&key->usage); | 773 | nklist->keys[nklist->delkey] = NULL; |
809 | nklist->keys[nklist->nkeys++] = key; | ||
810 | |||
811 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
812 | |||
813 | /* dispose of the old keyring list */ | ||
814 | if (klist) | ||
815 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); | ||
816 | } | 774 | } |
817 | 775 | ||
818 | done: | 776 | done: |
819 | ret = 0; | 777 | *_prealloc = nklist; |
820 | error2: | 778 | kleave(" = 0"); |
821 | up_write(&keyring_serialise_link_sem); | 779 | return 0; |
822 | error: | ||
823 | return ret; | ||
824 | 780 | ||
825 | error3: | 781 | error_quota: |
826 | /* undo the quota changes */ | 782 | /* undo the quota changes */ |
827 | key_payload_reserve(keyring, | 783 | key_payload_reserve(keyring, |
828 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 784 | keyring->datalen - KEYQUOTA_LINK_BYTES); |
829 | goto error2; | 785 | error_sem: |
786 | if (type == &key_type_keyring) | ||
787 | up_write(&keyring_serialise_link_sem); | ||
788 | error_krsem: | ||
789 | up_write(&keyring->sem); | ||
790 | kleave(" = %d", ret); | ||
791 | return ret; | ||
792 | } | ||
830 | 793 | ||
831 | } /* end __key_link() */ | 794 | /* |
795 | * check already instantiated keys aren't going to be a problem | ||
796 | * - the caller must have called __key_link_begin() | ||
797 | * - don't need to call this for keys that were created since __key_link_begin() | ||
798 | * was called | ||
799 | */ | ||
800 | int __key_link_check_live_key(struct key *keyring, struct key *key) | ||
801 | { | ||
802 | if (key->type == &key_type_keyring) | ||
803 | /* check that we aren't going to create a cycle by linking one | ||
804 | * keyring to another */ | ||
805 | return keyring_detect_cycle(keyring, key); | ||
806 | return 0; | ||
807 | } | ||
808 | |||
809 | /* | ||
810 | * link a key into to a keyring | ||
811 | * - must be called with __key_link_begin() having being called | ||
812 | * - discard already extant link to matching key if there is one | ||
813 | */ | ||
814 | void __key_link(struct key *keyring, struct key *key, | ||
815 | struct keyring_list **_prealloc) | ||
816 | { | ||
817 | struct keyring_list *klist, *nklist; | ||
818 | |||
819 | nklist = *_prealloc; | ||
820 | *_prealloc = NULL; | ||
821 | |||
822 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); | ||
823 | |||
824 | klist = rcu_dereference_protected(keyring->payload.subscriptions, | ||
825 | rwsem_is_locked(&keyring->sem)); | ||
826 | |||
827 | atomic_inc(&key->usage); | ||
828 | |||
829 | /* there's a matching key we can displace or an empty slot in a newly | ||
830 | * allocated list we can fill */ | ||
831 | if (nklist) { | ||
832 | kdebug("replace %hu/%hu/%hu", | ||
833 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | ||
834 | |||
835 | nklist->keys[nklist->delkey] = key; | ||
836 | |||
837 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
838 | |||
839 | /* dispose of the old keyring list and, if there was one, the | ||
840 | * displaced key */ | ||
841 | if (klist) { | ||
842 | kdebug("dispose %hu/%hu/%hu", | ||
843 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
844 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | ||
845 | } | ||
846 | } else { | ||
847 | /* there's sufficient slack space to append directly */ | ||
848 | klist->keys[klist->nkeys] = key; | ||
849 | smp_wmb(); | ||
850 | klist->nkeys++; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * finish linking a key into to a keyring | ||
856 | * - must be called with __key_link_begin() having being called | ||
857 | */ | ||
858 | void __key_link_end(struct key *keyring, struct key_type *type, | ||
859 | struct keyring_list *prealloc) | ||
860 | __releases(&keyring->sem) | ||
861 | { | ||
862 | BUG_ON(type == NULL); | ||
863 | BUG_ON(type->name == NULL); | ||
864 | kenter("%d,%s,%p", keyring->serial, type->name, prealloc); | ||
865 | |||
866 | if (type == &key_type_keyring) | ||
867 | up_write(&keyring_serialise_link_sem); | ||
868 | |||
869 | if (prealloc) { | ||
870 | kfree(prealloc); | ||
871 | key_payload_reserve(keyring, | ||
872 | keyring->datalen - KEYQUOTA_LINK_BYTES); | ||
873 | } | ||
874 | up_write(&keyring->sem); | ||
875 | } | ||
832 | 876 | ||
833 | /*****************************************************************************/ | ||
834 | /* | 877 | /* |
835 | * link a key to a keyring | 878 | * link a key to a keyring |
836 | */ | 879 | */ |
837 | int key_link(struct key *keyring, struct key *key) | 880 | int key_link(struct key *keyring, struct key *key) |
838 | { | 881 | { |
882 | struct keyring_list *prealloc; | ||
839 | int ret; | 883 | int ret; |
840 | 884 | ||
841 | key_check(keyring); | 885 | key_check(keyring); |
842 | key_check(key); | 886 | key_check(key); |
843 | 887 | ||
844 | down_write(&keyring->sem); | 888 | ret = __key_link_begin(keyring, key->type, key->description, &prealloc); |
845 | ret = __key_link(keyring, key); | 889 | if (ret == 0) { |
846 | up_write(&keyring->sem); | 890 | ret = __key_link_check_live_key(keyring, key); |
891 | if (ret == 0) | ||
892 | __key_link(keyring, key, &prealloc); | ||
893 | __key_link_end(keyring, key->type, prealloc); | ||
894 | } | ||
847 | 895 | ||
848 | return ret; | 896 | return ret; |
849 | 897 | } | |
850 | } /* end key_link() */ | ||
851 | 898 | ||
852 | EXPORT_SYMBOL(key_link); | 899 | EXPORT_SYMBOL(key_link); |
853 | 900 | ||