Commit 16feef43 authored by David Howells's avatar David Howells

KEYS: Consolidate the concept of an 'index key' for key access

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