Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -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"
	 */
	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
+3 −5
Original line number Diff line number Diff line
@@ -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,
+37 −35
Original line number Diff line number Diff line
@@ -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 @@ 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 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;
+19 −18
Original line number Diff line number Diff line
@@ -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 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
	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;
+8 −4
Original line number Diff line number Diff line
@@ -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 @@ static int construct_alloc_key(struct key_type *type,
		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;
	}