aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-01-08 04:02:45 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:13:53 -0500
commitcab8eb594e84b434d20412fc5a3985b0bee3ab9f (patch)
tree307dc5bf813effdcabe439a74ad2ae866516adb0
parent017679c4d45783158dba1dd6f79e712c22bb3d9a (diff)
[PATCH] keys: Discard duplicate keys from a keyring on link
Cause any links within a keyring to keys that match a key to be linked into that keyring to be discarded as a link to the new key is added. The match is contingent on the type and description strings being the same. This permits requests, adds and searches to displace negative, expired, revoked and dead keys easily. After some discussion it was concluded that duplicate valid keys should probably be discarded also as they would otherwise hide the new key. Since request_key() is intended to be the primary method by which keys are added to a keyring, duplicate valid keys wouldn't be an issue there as that function would return an existing match in preference to creating a new key. Signed-off-by: David Howells <dhowells@redhat.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Cc: Alexander Zangerl <az@bond.edu.au> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--Documentation/keys.txt4
-rw-r--r--security/keys/keyring.c87
2 files changed, 68 insertions, 23 deletions
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index c17c4ca74302..eeda00f82d2c 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -500,6 +500,10 @@ The keyctl syscall functions are:
500 The link procedure checks the nesting of the keyrings, returning ELOOP if 500 The link procedure checks the nesting of the keyrings, returning ELOOP if
501 it appears too deep or EDEADLK if the link would introduce a cycle. 501 it appears too deep or EDEADLK if the link would introduce a cycle.
502 502
503 Any links within the keyring to keys that match the new key in terms of
504 type and description will be discarded from the keyring as the new one is
505 added.
506
503 507
504 (*) Unlink a key or keyring from another keyring: 508 (*) Unlink a key or keyring from another keyring:
505 509
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 5d22c0388b32..09d92d52ef75 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -684,15 +684,31 @@ static void keyring_link_rcu_disposal(struct rcu_head *rcu)
684 684
685/*****************************************************************************/ 685/*****************************************************************************/
686/* 686/*
687 * dispose of a keyring list after the RCU grace period, freeing the unlinked
688 * key
689 */
690static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
691{
692 struct keyring_list *klist =
693 container_of(rcu, struct keyring_list, rcu);
694
695 key_put(klist->keys[klist->delkey]);
696 kfree(klist);
697
698} /* end keyring_unlink_rcu_disposal() */
699
700/*****************************************************************************/
701/*
687 * link a key into to a keyring 702 * link a key into to a keyring
688 * - must be called with the keyring's semaphore write-locked 703 * - must be called with the keyring's semaphore write-locked
704 * - discard already extant link to matching key if there is one
689 */ 705 */
690int __key_link(struct key *keyring, struct key *key) 706int __key_link(struct key *keyring, struct key *key)
691{ 707{
692 struct keyring_list *klist, *nklist; 708 struct keyring_list *klist, *nklist;
693 unsigned max; 709 unsigned max;
694 size_t size; 710 size_t size;
695 int ret; 711 int loop, ret;
696 712
697 ret = -EKEYREVOKED; 713 ret = -EKEYREVOKED;
698 if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 714 if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
@@ -714,6 +730,48 @@ int __key_link(struct key *keyring, struct key *key)
714 goto error2; 730 goto error2;
715 } 731 }
716 732
733 /* see if there's a matching key we can displace */
734 klist = keyring->payload.subscriptions;
735
736 if (klist && klist->nkeys > 0) {
737 struct key_type *type = key->type;
738
739 for (loop = klist->nkeys - 1; loop >= 0; loop--) {
740 if (klist->keys[loop]->type == type &&
741 strcmp(klist->keys[loop]->description,
742 key->description) == 0
743 ) {
744 /* found a match - replace with new key */
745 size = sizeof(struct key *) * klist->maxkeys;
746 size += sizeof(*klist);
747 BUG_ON(size > PAGE_SIZE);
748
749 ret = -ENOMEM;
750 nklist = kmalloc(size, GFP_KERNEL);
751 if (!nklist)
752 goto error2;
753
754 memcpy(nklist, klist, size);
755
756 /* replace matched key */
757 atomic_inc(&key->usage);
758 nklist->keys[loop] = key;
759
760 rcu_assign_pointer(
761 keyring->payload.subscriptions,
762 nklist);
763
764 /* dispose of the old keyring list and the
765 * displaced key */
766 klist->delkey = loop;
767 call_rcu(&klist->rcu,
768 keyring_unlink_rcu_disposal);
769
770 goto done;
771 }
772 }
773 }
774
717 /* check that we aren't going to overrun the user's quota */ 775 /* check that we aren't going to overrun the user's quota */
718 ret = key_payload_reserve(keyring, 776 ret = key_payload_reserve(keyring,
719 keyring->datalen + KEYQUOTA_LINK_BYTES); 777 keyring->datalen + KEYQUOTA_LINK_BYTES);
@@ -730,8 +788,6 @@ int __key_link(struct key *keyring, struct key *key)
730 smp_wmb(); 788 smp_wmb();
731 klist->nkeys++; 789 klist->nkeys++;
732 smp_wmb(); 790 smp_wmb();
733
734 ret = 0;
735 } 791 }
736 else { 792 else {
737 /* grow the key list */ 793 /* grow the key list */
@@ -769,16 +825,16 @@ int __key_link(struct key *keyring, struct key *key)
769 /* dispose of the old keyring list */ 825 /* dispose of the old keyring list */
770 if (klist) 826 if (klist)
771 call_rcu(&klist->rcu, keyring_link_rcu_disposal); 827 call_rcu(&klist->rcu, keyring_link_rcu_disposal);
772
773 ret = 0;
774 } 828 }
775 829
776 error2: 830done:
831 ret = 0;
832error2:
777 up_write(&keyring_serialise_link_sem); 833 up_write(&keyring_serialise_link_sem);
778 error: 834error:
779 return ret; 835 return ret;
780 836
781 error3: 837error3:
782 /* undo the quota changes */ 838 /* undo the quota changes */
783 key_payload_reserve(keyring, 839 key_payload_reserve(keyring,
784 keyring->datalen - KEYQUOTA_LINK_BYTES); 840 keyring->datalen - KEYQUOTA_LINK_BYTES);
@@ -809,21 +865,6 @@ EXPORT_SYMBOL(key_link);
809 865
810/*****************************************************************************/ 866/*****************************************************************************/
811/* 867/*
812 * dispose of a keyring list after the RCU grace period, freeing the unlinked
813 * key
814 */
815static 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 868 * unlink the first link to a key from a keyring
828 */ 869 */
829int key_unlink(struct key *keyring, struct key *key) 870int key_unlink(struct key *keyring, struct key *key)