diff options
-rw-r--r-- | include/linux/key.h | 21 | ||||
-rw-r--r-- | security/keys/internal.h | 8 | ||||
-rw-r--r-- | security/keys/key.c | 72 | ||||
-rw-r--r-- | security/keys/keyring.c | 37 | ||||
-rw-r--r-- | security/keys/request_key.c | 12 |
5 files changed, 83 insertions, 67 deletions
diff --git a/include/linux/key.h b/include/linux/key.h index 51bce2950de4..d573e820a23d 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -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 diff --git a/security/keys/internal.h b/security/keys/internal.h index 490aef5ba34b..77441dd1f9d4 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -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, diff --git a/security/keys/key.c b/security/keys/key.c index 8fb7c7bd4657..7e6bc396bb23 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -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; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index f78406372ebe..c7f59f9dd7b6 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -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; diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 172115b38054..586cb79ee82d 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -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; } |