KEYS: Consolidate the concept of an 'index key' for key access
authorDavid Howells <dhowells@redhat.com>
Tue, 24 Sep 2013 09:35:15 +0000 (10:35 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 24 Sep 2013 09:35:15 +0000 (10:35 +0100)
Consolidate the concept of an 'index key' for accessing keys.  The index key
is the search term needed to find a key directly - basically the key type and
the key description.  We can add to that the description length.

This will be useful when turning a keyring into an associative array rather
than just a pointer block.

Signed-off-by: David Howells <dhowells@redhat.com>
include/linux/key.h
security/keys/internal.h
security/keys/key.c
security/keys/keyring.c
security/keys/request_key.c

index 51bce2950de4389cc018f56eafd1ca3cd40cf5c3..d573e820a23d8808cf294d9398e563d6c931319a 100644 (file)
@@ -82,6 +82,12 @@ struct key_owner;
 struct keyring_list;
 struct keyring_name;
 
+struct keyring_index_key {
+       struct key_type         *type;
+       const char              *description;
+       size_t                  desc_len;
+};
+
 /*****************************************************************************/
 /*
  * key reference with possession attribute handling
@@ -129,7 +135,6 @@ struct key {
                struct list_head graveyard_link;
                struct rb_node  serial_node;
        };
-       struct key_type         *type;          /* type of key */
        struct rw_semaphore     sem;            /* change vs change sem */
        struct key_user         *user;          /* owner of this key */
        void                    *security;      /* security data for this key */
@@ -163,12 +168,18 @@ struct key {
 #define KEY_FLAG_ROOT_CAN_CLEAR        6       /* set if key can be cleared by root without permission */
 #define KEY_FLAG_INVALIDATED   7       /* set if key has been invalidated */
 
-       /* the description string
-        * - this is used to match a key against search criteria
-        * - this should be a printable string
+       /* the key type and key description string
+        * - the desc is used to match a key against search criteria
+        * - it should be a printable string
         * - eg: for krb5 AFS, this might be "afs@REDHAT.COM"
         */
-       char                    *description;
+       union {
+               struct keyring_index_key index_key;
+               struct {
+                       struct key_type *type;          /* type of key */
+                       char            *description;
+               };
+       };
 
        /* type specific data
         * - this is used by the keyring type to index the name
index 490aef5ba34be4abefa35396239f9bd1c535ddd0..77441dd1f9d43035e93b0e10b73023aaeca66388 100644 (file)
@@ -89,19 +89,17 @@ extern struct key_type *key_type_lookup(const char *type);
 extern void key_type_put(struct key_type *ktype);
 
 extern int __key_link_begin(struct key *keyring,
-                           const struct key_type *type,
-                           const char *description,
+                           const struct keyring_index_key *index_key,
                            unsigned long *_prealloc);
 extern int __key_link_check_live_key(struct key *keyring, struct key *key);
 extern void __key_link(struct key *keyring, struct key *key,
                       unsigned long *_prealloc);
 extern void __key_link_end(struct key *keyring,
-                          struct key_type *type,
+                          const struct keyring_index_key *index_key,
                           unsigned long prealloc);
 
 extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
-                                     const struct key_type *type,
-                                     const char *description,
+                                     const struct keyring_index_key *index_key,
                                      key_perm_t perm);
 
 extern struct key *keyring_search_instkey(struct key *keyring,
index 8fb7c7bd465769cb5dca49e6d6f1ad011c75de63..7e6bc396bb23fd65b5b2ffc99b9c1756b65c72c8 100644 (file)
@@ -242,8 +242,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
                }
        }
 
-       desclen = strlen(desc) + 1;
-       quotalen = desclen + type->def_datalen;
+       desclen = strlen(desc);
+       quotalen = desclen + 1 + type->def_datalen;
 
        /* get hold of the key tracking for this user */
        user = key_user_lookup(uid);
@@ -277,7 +277,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
                goto no_memory_2;
 
        if (desc) {
-               key->description = kmemdup(desc, desclen, GFP_KERNEL);
+               key->index_key.desc_len = desclen;
+               key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL);
                if (!key->description)
                        goto no_memory_3;
        }
@@ -285,7 +286,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        atomic_set(&key->usage, 1);
        init_rwsem(&key->sem);
        lockdep_set_class(&key->sem, &type->lock_class);
-       key->type = type;
+       key->index_key.type = type;
        key->user = user;
        key->quotalen = quotalen;
        key->datalen = type->def_datalen;
@@ -489,8 +490,7 @@ int key_instantiate_and_link(struct key *key,
        }
 
        if (keyring) {
-               ret = __key_link_begin(keyring, key->type, key->description,
-                                      &prealloc);
+               ret = __key_link_begin(keyring, &key->index_key, &prealloc);
                if (ret < 0)
                        goto error_free_preparse;
        }
@@ -499,7 +499,7 @@ int key_instantiate_and_link(struct key *key,
                                         &prealloc);
 
        if (keyring)
-               __key_link_end(keyring, key->type, prealloc);
+               __key_link_end(keyring, &key->index_key, prealloc);
 
 error_free_preparse:
        if (key->type->preparse)
@@ -548,8 +548,7 @@ int key_reject_and_link(struct key *key,
        ret = -EBUSY;
 
        if (keyring)
-               link_ret = __key_link_begin(keyring, key->type,
-                                           key->description, &prealloc);
+               link_ret = __key_link_begin(keyring, &key->index_key, &prealloc);
 
        mutex_lock(&key_construction_mutex);
 
@@ -581,7 +580,7 @@ int key_reject_and_link(struct key *key,
        mutex_unlock(&key_construction_mutex);
 
        if (keyring)
-               __key_link_end(keyring, key->type, prealloc);
+               __key_link_end(keyring, &key->index_key, prealloc);
 
        /* wake up anyone waiting for a key to be constructed */
        if (awaken)
@@ -780,25 +779,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                               key_perm_t perm,
                               unsigned long flags)
 {
-       unsigned long prealloc;
+       struct keyring_index_key index_key = {
+               .description    = description,
+       };
        struct key_preparsed_payload prep;
        const struct cred *cred = current_cred();
-       struct key_type *ktype;
+       unsigned long prealloc;
        struct key *keyring, *key = NULL;
        key_ref_t key_ref;
        int ret;
 
        /* look up the key type to see if it's one of the registered kernel
         * types */
-       ktype = key_type_lookup(type);
-       if (IS_ERR(ktype)) {
+       index_key.type = key_type_lookup(type);
+       if (IS_ERR(index_key.type)) {
                key_ref = ERR_PTR(-ENODEV);
                goto error;
        }
 
        key_ref = ERR_PTR(-EINVAL);
-       if (!ktype->match || !ktype->instantiate ||
-           (!description && !ktype->preparse))
+       if (!index_key.type->match || !index_key.type->instantiate ||
+           (!index_key.description && !index_key.type->preparse))
                goto error_put_type;
 
        keyring = key_ref_to_ptr(keyring_ref);
@@ -812,21 +813,22 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        memset(&prep, 0, sizeof(prep));
        prep.data = payload;
        prep.datalen = plen;
-       prep.quotalen = ktype->def_datalen;
-       if (ktype->preparse) {
-               ret = ktype->preparse(&prep);
+       prep.quotalen = index_key.type->def_datalen;
+       if (index_key.type->preparse) {
+               ret = index_key.type->preparse(&prep);
                if (ret < 0) {
                        key_ref = ERR_PTR(ret);
                        goto error_put_type;
                }
-               if (!description)
-                       description = prep.description;
+               if (!index_key.description)
+                       index_key.description = prep.description;
                key_ref = ERR_PTR(-EINVAL);
-               if (!description)
+               if (!index_key.description)
                        goto error_free_prep;
        }
+       index_key.desc_len = strlen(index_key.description);
 
-       ret = __key_link_begin(keyring, ktype, description, &prealloc);
+       ret = __key_link_begin(keyring, &index_key, &prealloc);
        if (ret < 0) {
                key_ref = ERR_PTR(ret);
                goto error_free_prep;
@@ -844,9 +846,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
         * key of the same type and description in the destination keyring and
         * update that instead if possible
         */
-       if (ktype->update) {
-               key_ref = __keyring_search_one(keyring_ref, ktype, description,
-                                              0);
+       if (index_key.type->update) {
+               key_ref = __keyring_search_one(keyring_ref, &index_key, 0);
                if (!IS_ERR(key_ref))
                        goto found_matching_key;
        }
@@ -856,16 +857,17 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
                perm |= KEY_USR_VIEW;
 
-               if (ktype->read)
+               if (index_key.type->read)
                        perm |= KEY_POS_READ;
 
-               if (ktype == &key_type_keyring || ktype->update)
+               if (index_key.type == &key_type_keyring ||
+                   index_key.type->update)
                        perm |= KEY_POS_WRITE;
        }
 
        /* allocate a new key */
-       key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
-                       perm, flags);
+       key = key_alloc(index_key.type, index_key.description,
+                       cred->fsuid, cred->fsgid, cred, perm, flags);
        if (IS_ERR(key)) {
                key_ref = ERR_CAST(key);
                goto error_link_end;
@@ -882,12 +884,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
        key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
 
 error_link_end:
-       __key_link_end(keyring, ktype, prealloc);
+       __key_link_end(keyring, &index_key, prealloc);
 error_free_prep:
-       if (ktype->preparse)
-               ktype->free_preparse(&prep);
+       if (index_key.type->preparse)
+               index_key.type->free_preparse(&prep);
 error_put_type:
-       key_type_put(ktype);
+       key_type_put(index_key.type);
 error:
        return key_ref;
 
@@ -895,7 +897,7 @@ error:
        /* we found a matching key, so we're going to try to update it
         * - we can drop the locks first as we have the key pinned
         */
-       __key_link_end(keyring, ktype, prealloc);
+       __key_link_end(keyring, &index_key, prealloc);
 
        key_ref = __key_update(key_ref, &prep);
        goto error_free_prep;
index f78406372ebe402c1a51f0864b7562ad275cecf5..c7f59f9dd7b6c61edaf1900eb8458eb8a7e32a6b 100644 (file)
@@ -538,8 +538,7 @@ EXPORT_SYMBOL(keyring_search);
  * to the returned key reference.
  */
 key_ref_t __keyring_search_one(key_ref_t keyring_ref,
-                              const struct key_type *ktype,
-                              const char *description,
+                              const struct keyring_index_key *index_key,
                               key_perm_t perm)
 {
        struct keyring_list *klist;
@@ -558,9 +557,9 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref,
                smp_rmb();
                for (loop = 0; loop < nkeys ; loop++) {
                        key = rcu_dereference(klist->keys[loop]);
-                       if (key->type == ktype &&
+                       if (key->type == index_key->type &&
                            (!key->type->match ||
-                            key->type->match(key, description)) &&
+                            key->type->match(key, index_key->description)) &&
                            key_permission(make_key_ref(key, possessed),
                                           perm) == 0 &&
                            !(key->flags & ((1 << KEY_FLAG_INVALIDATED) |
@@ -747,8 +746,8 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
 /*
  * Preallocate memory so that a key can be linked into to a keyring.
  */
-int __key_link_begin(struct key *keyring, const struct key_type *type,
-                    const char *description, unsigned long *_prealloc)
+int __key_link_begin(struct key *keyring, const struct keyring_index_key *index_key,
+                    unsigned long *_prealloc)
        __acquires(&keyring->sem)
        __acquires(&keyring_serialise_link_sem)
 {
@@ -759,7 +758,8 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
        size_t size;
        int loop, lru, ret;
 
-       kenter("%d,%s,%s,", key_serial(keyring), type->name, description);
+       kenter("%d,%s,%s,",
+              key_serial(keyring), index_key->type->name, index_key->description);
 
        if (keyring->type != &key_type_keyring)
                return -ENOTDIR;
@@ -772,7 +772,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
 
        /* serialise link/link calls to prevent parallel calls causing a cycle
         * when linking two keyring in opposite orders */
-       if (type == &key_type_keyring)
+       if (index_key->type == &key_type_keyring)
                down_write(&keyring_serialise_link_sem);
 
        klist = rcu_dereference_locked_keyring(keyring);
@@ -784,8 +784,8 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
                for (loop = klist->nkeys - 1; loop >= 0; loop--) {
                        struct key *key = rcu_deref_link_locked(klist, loop,
                                                                keyring);
-                       if (key->type == type &&
-                           strcmp(key->description, description) == 0) {
+                       if (key->type == index_key->type &&
+                           strcmp(key->description, index_key->description) == 0) {
                                /* Found a match - we'll replace the link with
                                 * one to the new key.  We record the slot
                                 * position.
@@ -865,7 +865,7 @@ error_quota:
        key_payload_reserve(keyring,
                            keyring->datalen - KEYQUOTA_LINK_BYTES);
 error_sem:
-       if (type == &key_type_keyring)
+       if (index_key->type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 error_krsem:
        up_write(&keyring->sem);
@@ -957,16 +957,17 @@ void __key_link(struct key *keyring, struct key *key,
  *
  * Must be called with __key_link_begin() having being called.
  */
-void __key_link_end(struct key *keyring, struct key_type *type,
+void __key_link_end(struct key *keyring,
+                   const struct keyring_index_key *index_key,
                    unsigned long prealloc)
        __releases(&keyring->sem)
        __releases(&keyring_serialise_link_sem)
 {
-       BUG_ON(type == NULL);
-       BUG_ON(type->name == NULL);
-       kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
+       BUG_ON(index_key->type == NULL);
+       BUG_ON(index_key->type->name == NULL);
+       kenter("%d,%s,%lx", keyring->serial, index_key->type->name, prealloc);
 
-       if (type == &key_type_keyring)
+       if (index_key->type == &key_type_keyring)
                up_write(&keyring_serialise_link_sem);
 
        if (prealloc) {
@@ -1007,12 +1008,12 @@ int key_link(struct key *keyring, struct key *key)
        key_check(keyring);
        key_check(key);
 
-       ret = __key_link_begin(keyring, key->type, key->description, &prealloc);
+       ret = __key_link_begin(keyring, &key->index_key, &prealloc);
        if (ret == 0) {
                ret = __key_link_check_live_key(keyring, key);
                if (ret == 0)
                        __key_link(keyring, key, &prealloc);
-               __key_link_end(keyring, key->type, prealloc);
+               __key_link_end(keyring, &key->index_key, prealloc);
        }
 
        return ret;
index 172115b38054f0975dbffc7aebb60d440271b03c..586cb79ee82dcfdff410b7cbd4fdb59b33adfb24 100644 (file)
@@ -352,6 +352,11 @@ static int construct_alloc_key(struct key_type *type,
                               struct key_user *user,
                               struct key **_key)
 {
+       const struct keyring_index_key index_key = {
+               .type           = type,
+               .description    = description,
+               .desc_len       = strlen(description),
+       };
        const struct cred *cred = current_cred();
        unsigned long prealloc;
        struct key *key;
@@ -379,8 +384,7 @@ static int construct_alloc_key(struct key_type *type,
        set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
 
        if (dest_keyring) {
-               ret = __key_link_begin(dest_keyring, type, description,
-                                      &prealloc);
+               ret = __key_link_begin(dest_keyring, &index_key, &prealloc);
                if (ret < 0)
                        goto link_prealloc_failed;
        }
@@ -400,7 +404,7 @@ static int construct_alloc_key(struct key_type *type,
 
        mutex_unlock(&key_construction_mutex);
        if (dest_keyring)
-               __key_link_end(dest_keyring, type, prealloc);
+               __key_link_end(dest_keyring, &index_key, prealloc);
        mutex_unlock(&user->cons_lock);
        *_key = key;
        kleave(" = 0 [%d]", key_serial(key));
@@ -416,7 +420,7 @@ key_already_present:
                ret = __key_link_check_live_key(dest_keyring, key);
                if (ret == 0)
                        __key_link(dest_keyring, key, &prealloc);
-               __key_link_end(dest_keyring, type, prealloc);
+               __key_link_end(dest_keyring, &index_key, prealloc);
                if (ret < 0)
                        goto link_check_failed;
        }