mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	KEYS: Do preallocation for __key_link()
Do preallocation for __key_link() so that the various callers in request_key.c can deal with any errors from this source before attempting to construct a key. This allows them to assume that the actual linkage step is guaranteed to be successful. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
		
							parent
							
								
									043b4d40f5
								
							
						
					
					
						commit
						f70e2e0619
					
				
					 4 changed files with 215 additions and 130 deletions
				
			
		| 
						 | 
					@ -87,7 +87,16 @@ extern wait_queue_head_t request_key_conswq;
 | 
				
			||||||
extern struct key_type *key_type_lookup(const char *type);
 | 
					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(struct key *keyring, struct key *key);
 | 
					extern int __key_link_begin(struct key *keyring,
 | 
				
			||||||
 | 
								    const struct key_type *type,
 | 
				
			||||||
 | 
								    const char *description,
 | 
				
			||||||
 | 
								    struct keyring_list **_prealloc);
 | 
				
			||||||
 | 
					extern int __key_link_check_live_key(struct key *keyring, struct key *key);
 | 
				
			||||||
 | 
					extern void __key_link(struct key *keyring, struct key *key,
 | 
				
			||||||
 | 
							       struct keyring_list **_prealloc);
 | 
				
			||||||
 | 
					extern void __key_link_end(struct key *keyring,
 | 
				
			||||||
 | 
								   struct key_type *type,
 | 
				
			||||||
 | 
								   struct keyring_list *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 key_type *type,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -398,7 +398,8 @@ static int __key_instantiate_and_link(struct key *key,
 | 
				
			||||||
				      const void *data,
 | 
									      const void *data,
 | 
				
			||||||
				      size_t datalen,
 | 
									      size_t datalen,
 | 
				
			||||||
				      struct key *keyring,
 | 
									      struct key *keyring,
 | 
				
			||||||
				      struct key *authkey)
 | 
									      struct key *authkey,
 | 
				
			||||||
 | 
									      struct keyring_list **_prealloc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret, awaken;
 | 
						int ret, awaken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -425,7 +426,7 @@ static int __key_instantiate_and_link(struct key *key,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* and link it into the destination keyring */
 | 
								/* and link it into the destination keyring */
 | 
				
			||||||
			if (keyring)
 | 
								if (keyring)
 | 
				
			||||||
				ret = __key_link(keyring, key);
 | 
									__key_link(keyring, key, _prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/* disable the authorisation key */
 | 
								/* disable the authorisation key */
 | 
				
			||||||
			if (authkey)
 | 
								if (authkey)
 | 
				
			||||||
| 
						 | 
					@ -453,15 +454,21 @@ int key_instantiate_and_link(struct key *key,
 | 
				
			||||||
			     struct key *keyring,
 | 
								     struct key *keyring,
 | 
				
			||||||
			     struct key *authkey)
 | 
								     struct key *authkey)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct keyring_list *prealloc;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (keyring)
 | 
						if (keyring) {
 | 
				
			||||||
		down_write(&keyring->sem);
 | 
							ret = __key_link_begin(keyring, key->type, key->description,
 | 
				
			||||||
 | 
									       &prealloc);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey);
 | 
						ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
 | 
				
			||||||
 | 
										 &prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (keyring)
 | 
						if (keyring)
 | 
				
			||||||
		up_write(&keyring->sem);
 | 
							__key_link_end(keyring, key->type, prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -478,8 +485,9 @@ int key_negate_and_link(struct key *key,
 | 
				
			||||||
			struct key *keyring,
 | 
								struct key *keyring,
 | 
				
			||||||
			struct key *authkey)
 | 
								struct key *authkey)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct keyring_list *prealloc;
 | 
				
			||||||
	struct timespec now;
 | 
						struct timespec now;
 | 
				
			||||||
	int ret, awaken;
 | 
						int ret, awaken, link_ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key_check(key);
 | 
						key_check(key);
 | 
				
			||||||
	key_check(keyring);
 | 
						key_check(keyring);
 | 
				
			||||||
| 
						 | 
					@ -488,7 +496,8 @@ int key_negate_and_link(struct key *key,
 | 
				
			||||||
	ret = -EBUSY;
 | 
						ret = -EBUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (keyring)
 | 
						if (keyring)
 | 
				
			||||||
		down_write(&keyring->sem);
 | 
							link_ret = __key_link_begin(keyring, key->type,
 | 
				
			||||||
 | 
										    key->description, &prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_lock(&key_construction_mutex);
 | 
						mutex_lock(&key_construction_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -508,8 +517,8 @@ int key_negate_and_link(struct key *key,
 | 
				
			||||||
		ret = 0;
 | 
							ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* and link it into the destination keyring */
 | 
							/* and link it into the destination keyring */
 | 
				
			||||||
		if (keyring)
 | 
							if (keyring && link_ret == 0)
 | 
				
			||||||
			ret = __key_link(keyring, key);
 | 
								__key_link(keyring, key, &prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* disable the authorisation key */
 | 
							/* disable the authorisation key */
 | 
				
			||||||
		if (authkey)
 | 
							if (authkey)
 | 
				
			||||||
| 
						 | 
					@ -519,13 +528,13 @@ int key_negate_and_link(struct key *key,
 | 
				
			||||||
	mutex_unlock(&key_construction_mutex);
 | 
						mutex_unlock(&key_construction_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (keyring)
 | 
						if (keyring)
 | 
				
			||||||
		up_write(&keyring->sem);
 | 
							__key_link_end(keyring, key->type, 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)
 | 
				
			||||||
		wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 | 
							wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret == 0 ? link_ret : ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} /* end key_negate_and_link() */
 | 
					} /* end key_negate_and_link() */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -749,6 +758,7 @@ 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)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct keyring_list *prealloc;
 | 
				
			||||||
	const struct cred *cred = current_cred();
 | 
						const struct cred *cred = current_cred();
 | 
				
			||||||
	struct key_type *ktype;
 | 
						struct key_type *ktype;
 | 
				
			||||||
	struct key *keyring, *key = NULL;
 | 
						struct key *keyring, *key = NULL;
 | 
				
			||||||
| 
						 | 
					@ -775,7 +785,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 | 
				
			||||||
	if (keyring->type != &key_type_keyring)
 | 
						if (keyring->type != &key_type_keyring)
 | 
				
			||||||
		goto error_2;
 | 
							goto error_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down_write(&keyring->sem);
 | 
						ret = __key_link_begin(keyring, ktype, description, &prealloc);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							goto error_2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* if we're going to allocate a new key, we're going to have
 | 
						/* if we're going to allocate a new key, we're going to have
 | 
				
			||||||
	 * to modify the keyring */
 | 
						 * to modify the keyring */
 | 
				
			||||||
| 
						 | 
					@ -817,7 +829,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* instantiate it and link it into the target keyring */
 | 
						/* instantiate it and link it into the target keyring */
 | 
				
			||||||
	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
 | 
						ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
 | 
				
			||||||
 | 
										 &prealloc);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		key_put(key);
 | 
							key_put(key);
 | 
				
			||||||
		key_ref = ERR_PTR(ret);
 | 
							key_ref = ERR_PTR(ret);
 | 
				
			||||||
| 
						 | 
					@ -827,7 +840,7 @@ 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_3:
 | 
					 error_3:
 | 
				
			||||||
	up_write(&keyring->sem);
 | 
						__key_link_end(keyring, ktype, prealloc);
 | 
				
			||||||
 error_2:
 | 
					 error_2:
 | 
				
			||||||
	key_type_put(ktype);
 | 
						key_type_put(ktype);
 | 
				
			||||||
 error:
 | 
					 error:
 | 
				
			||||||
| 
						 | 
					@ -837,7 +850,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
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	up_write(&keyring->sem);
 | 
						__key_link_end(keyring, ktype, prealloc);
 | 
				
			||||||
	key_type_put(ktype);
 | 
						key_type_put(ktype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key_ref = __key_update(key_ref, payload, plen);
 | 
						key_ref = __key_update(key_ref, payload, plen);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -660,20 +660,6 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} /* end keyring_detect_cycle() */
 | 
					} /* end keyring_detect_cycle() */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*****************************************************************************/
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * dispose of a keyring list after the RCU grace period
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void keyring_link_rcu_disposal(struct rcu_head *rcu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct keyring_list *klist =
 | 
					 | 
				
			||||||
		container_of(rcu, struct keyring_list, rcu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	kfree(klist);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
} /* end keyring_link_rcu_disposal() */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*****************************************************************************/
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * dispose of a keyring list after the RCU grace period, freeing the unlinked
 | 
					 * dispose of a keyring list after the RCU grace period, freeing the unlinked
 | 
				
			||||||
 * key
 | 
					 * key
 | 
				
			||||||
| 
						 | 
					@ -683,56 +669,51 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
 | 
				
			||||||
	struct keyring_list *klist =
 | 
						struct keyring_list *klist =
 | 
				
			||||||
		container_of(rcu, struct keyring_list, rcu);
 | 
							container_of(rcu, struct keyring_list, rcu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key_put(klist->keys[klist->delkey]);
 | 
						if (klist->delkey != USHORT_MAX)
 | 
				
			||||||
 | 
							key_put(klist->keys[klist->delkey]);
 | 
				
			||||||
	kfree(klist);
 | 
						kfree(klist);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} /* end keyring_unlink_rcu_disposal() */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*****************************************************************************/
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * link a key into to a keyring
 | 
					 * preallocate memory so that a key can be linked into to a keyring
 | 
				
			||||||
 * - must be called with the keyring's semaphore write-locked
 | 
					 | 
				
			||||||
 * - discard already extant link to matching key if there is one
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int __key_link(struct key *keyring, struct key *key)
 | 
					int __key_link_begin(struct key *keyring, const struct key_type *type,
 | 
				
			||||||
 | 
							     const char *description,
 | 
				
			||||||
 | 
							     struct keyring_list **_prealloc)
 | 
				
			||||||
 | 
						__acquires(&keyring->sem)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct keyring_list *klist, *nklist;
 | 
						struct keyring_list *klist, *nklist;
 | 
				
			||||||
	unsigned max;
 | 
						unsigned max;
 | 
				
			||||||
	size_t size;
 | 
						size_t size;
 | 
				
			||||||
	int loop, ret;
 | 
						int loop, ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kenter("%d,%s,%s,", key_serial(keyring), type->name, description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (keyring->type != &key_type_keyring)
 | 
				
			||||||
 | 
							return -ENOTDIR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						down_write(&keyring->sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = -EKEYREVOKED;
 | 
						ret = -EKEYREVOKED;
 | 
				
			||||||
	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
 | 
						if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
 | 
				
			||||||
		goto error;
 | 
							goto error_krsem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = -ENOTDIR;
 | 
						/* serialise link/link calls to prevent parallel calls causing a cycle
 | 
				
			||||||
	if (keyring->type != &key_type_keyring)
 | 
						 * when linking two keyring in opposite orders */
 | 
				
			||||||
		goto error;
 | 
						if (type == &key_type_keyring)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* do some special keyring->keyring link checks */
 | 
					 | 
				
			||||||
	if (key->type == &key_type_keyring) {
 | 
					 | 
				
			||||||
		/* serialise link/link calls to prevent parallel calls causing
 | 
					 | 
				
			||||||
		 * a cycle when applied to two keyring in opposite orders */
 | 
					 | 
				
			||||||
		down_write(&keyring_serialise_link_sem);
 | 
							down_write(&keyring_serialise_link_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* check that we aren't going to create a cycle adding one
 | 
						klist = rcu_dereference_locked_keyring(keyring);
 | 
				
			||||||
		 * keyring to another */
 | 
					 | 
				
			||||||
		ret = keyring_detect_cycle(keyring, key);
 | 
					 | 
				
			||||||
		if (ret < 0)
 | 
					 | 
				
			||||||
			goto error2;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* see if there's a matching key we can displace */
 | 
						/* see if there's a matching key we can displace */
 | 
				
			||||||
	klist = rcu_dereference_locked_keyring(keyring);
 | 
					 | 
				
			||||||
	if (klist && klist->nkeys > 0) {
 | 
						if (klist && klist->nkeys > 0) {
 | 
				
			||||||
		struct key_type *type = key->type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (loop = klist->nkeys - 1; loop >= 0; loop--) {
 | 
							for (loop = klist->nkeys - 1; loop >= 0; loop--) {
 | 
				
			||||||
			if (klist->keys[loop]->type == type &&
 | 
								if (klist->keys[loop]->type == type &&
 | 
				
			||||||
			    strcmp(klist->keys[loop]->description,
 | 
								    strcmp(klist->keys[loop]->description,
 | 
				
			||||||
				   key->description) == 0
 | 
									   description) == 0
 | 
				
			||||||
			    ) {
 | 
								    ) {
 | 
				
			||||||
				/* found a match - replace with new key */
 | 
									/* found a match - we'll replace this one with
 | 
				
			||||||
 | 
									 * the new key */
 | 
				
			||||||
				size = sizeof(struct key *) * klist->maxkeys;
 | 
									size = sizeof(struct key *) * klist->maxkeys;
 | 
				
			||||||
				size += sizeof(*klist);
 | 
									size += sizeof(*klist);
 | 
				
			||||||
				BUG_ON(size > PAGE_SIZE);
 | 
									BUG_ON(size > PAGE_SIZE);
 | 
				
			||||||
| 
						 | 
					@ -740,22 +721,10 @@ int __key_link(struct key *keyring, struct key *key)
 | 
				
			||||||
				ret = -ENOMEM;
 | 
									ret = -ENOMEM;
 | 
				
			||||||
				nklist = kmemdup(klist, size, GFP_KERNEL);
 | 
									nklist = kmemdup(klist, size, GFP_KERNEL);
 | 
				
			||||||
				if (!nklist)
 | 
									if (!nklist)
 | 
				
			||||||
					goto error2;
 | 
										goto error_sem;
 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* replace matched key */
 | 
					 | 
				
			||||||
				atomic_inc(&key->usage);
 | 
					 | 
				
			||||||
				nklist->keys[loop] = key;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				rcu_assign_pointer(
 | 
					 | 
				
			||||||
					keyring->payload.subscriptions,
 | 
					 | 
				
			||||||
					nklist);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				/* dispose of the old keyring list and the
 | 
					 | 
				
			||||||
				 * displaced key */
 | 
					 | 
				
			||||||
				klist->delkey = loop;
 | 
					 | 
				
			||||||
				call_rcu(&klist->rcu,
 | 
					 | 
				
			||||||
					 keyring_unlink_rcu_disposal);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* note replacement slot */
 | 
				
			||||||
 | 
									klist->delkey = nklist->delkey = loop;
 | 
				
			||||||
				goto done;
 | 
									goto done;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -765,16 +734,11 @@ int __key_link(struct key *keyring, struct key *key)
 | 
				
			||||||
	ret = key_payload_reserve(keyring,
 | 
						ret = key_payload_reserve(keyring,
 | 
				
			||||||
				  keyring->datalen + KEYQUOTA_LINK_BYTES);
 | 
									  keyring->datalen + KEYQUOTA_LINK_BYTES);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto error2;
 | 
							goto error_sem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (klist && klist->nkeys < klist->maxkeys) {
 | 
						if (klist && klist->nkeys < klist->maxkeys) {
 | 
				
			||||||
		/* there's sufficient slack space to add directly */
 | 
							/* there's sufficient slack space to append directly */
 | 
				
			||||||
		atomic_inc(&key->usage);
 | 
							nklist = NULL;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		klist->keys[klist->nkeys] = key;
 | 
					 | 
				
			||||||
		smp_wmb();
 | 
					 | 
				
			||||||
		klist->nkeys++;
 | 
					 | 
				
			||||||
		smp_wmb();
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* grow the key list */
 | 
							/* grow the key list */
 | 
				
			||||||
		max = 4;
 | 
							max = 4;
 | 
				
			||||||
| 
						 | 
					@ -782,71 +746,155 @@ int __key_link(struct key *keyring, struct key *key)
 | 
				
			||||||
			max += klist->maxkeys;
 | 
								max += klist->maxkeys;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = -ENFILE;
 | 
							ret = -ENFILE;
 | 
				
			||||||
		if (max > 65535)
 | 
							if (max > USHORT_MAX - 1)
 | 
				
			||||||
			goto error3;
 | 
								goto error_quota;
 | 
				
			||||||
		size = sizeof(*klist) + sizeof(struct key *) * max;
 | 
							size = sizeof(*klist) + sizeof(struct key *) * max;
 | 
				
			||||||
		if (size > PAGE_SIZE)
 | 
							if (size > PAGE_SIZE)
 | 
				
			||||||
			goto error3;
 | 
								goto error_quota;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = -ENOMEM;
 | 
							ret = -ENOMEM;
 | 
				
			||||||
		nklist = kmalloc(size, GFP_KERNEL);
 | 
							nklist = kmalloc(size, GFP_KERNEL);
 | 
				
			||||||
		if (!nklist)
 | 
							if (!nklist)
 | 
				
			||||||
			goto error3;
 | 
								goto error_quota;
 | 
				
			||||||
		nklist->maxkeys = max;
 | 
					 | 
				
			||||||
		nklist->nkeys = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nklist->maxkeys = max;
 | 
				
			||||||
		if (klist) {
 | 
							if (klist) {
 | 
				
			||||||
			nklist->nkeys = klist->nkeys;
 | 
								memcpy(nklist->keys, klist->keys,
 | 
				
			||||||
			memcpy(nklist->keys,
 | 
					 | 
				
			||||||
			       klist->keys,
 | 
					 | 
				
			||||||
			       sizeof(struct key *) * klist->nkeys);
 | 
								       sizeof(struct key *) * klist->nkeys);
 | 
				
			||||||
 | 
								nklist->delkey = klist->nkeys;
 | 
				
			||||||
 | 
								nklist->nkeys = klist->nkeys + 1;
 | 
				
			||||||
 | 
								klist->delkey = USHORT_MAX;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								nklist->nkeys = 1;
 | 
				
			||||||
 | 
								nklist->delkey = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* add the key into the new space */
 | 
							/* add the key into the new space */
 | 
				
			||||||
		atomic_inc(&key->usage);
 | 
							nklist->keys[nklist->delkey] = NULL;
 | 
				
			||||||
		nklist->keys[nklist->nkeys++] = key;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rcu_assign_pointer(keyring->payload.subscriptions, nklist);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* dispose of the old keyring list */
 | 
					 | 
				
			||||||
		if (klist)
 | 
					 | 
				
			||||||
			call_rcu(&klist->rcu, keyring_link_rcu_disposal);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
	ret = 0;
 | 
						*_prealloc = nklist;
 | 
				
			||||||
error2:
 | 
						kleave(" = 0");
 | 
				
			||||||
	if (key->type == &key_type_keyring)
 | 
						return 0;
 | 
				
			||||||
		up_write(&keyring_serialise_link_sem);
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
error3:
 | 
					error_quota:
 | 
				
			||||||
	/* undo the quota changes */
 | 
						/* undo the quota changes */
 | 
				
			||||||
	key_payload_reserve(keyring,
 | 
						key_payload_reserve(keyring,
 | 
				
			||||||
			    keyring->datalen - KEYQUOTA_LINK_BYTES);
 | 
								    keyring->datalen - KEYQUOTA_LINK_BYTES);
 | 
				
			||||||
	goto error2;
 | 
					error_sem:
 | 
				
			||||||
 | 
						if (type == &key_type_keyring)
 | 
				
			||||||
 | 
							up_write(&keyring_serialise_link_sem);
 | 
				
			||||||
 | 
					error_krsem:
 | 
				
			||||||
 | 
						up_write(&keyring->sem);
 | 
				
			||||||
 | 
						kleave(" = %d", ret);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} /* end __key_link() */
 | 
					/*
 | 
				
			||||||
 | 
					 * check already instantiated keys aren't going to be a problem
 | 
				
			||||||
 | 
					 * - the caller must have called __key_link_begin()
 | 
				
			||||||
 | 
					 * - don't need to call this for keys that were created since __key_link_begin()
 | 
				
			||||||
 | 
					 *   was called
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int __key_link_check_live_key(struct key *keyring, struct key *key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (key->type == &key_type_keyring)
 | 
				
			||||||
 | 
							/* check that we aren't going to create a cycle by linking one
 | 
				
			||||||
 | 
							 * keyring to another */
 | 
				
			||||||
 | 
							return keyring_detect_cycle(keyring, key);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * link a key into to a keyring
 | 
				
			||||||
 | 
					 * - must be called with __key_link_begin() having being called
 | 
				
			||||||
 | 
					 * - discard already extant link to matching key if there is one
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void __key_link(struct key *keyring, struct key *key,
 | 
				
			||||||
 | 
							struct keyring_list **_prealloc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct keyring_list *klist, *nklist;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						nklist = *_prealloc;
 | 
				
			||||||
 | 
						*_prealloc = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						klist = rcu_dereference_protected(keyring->payload.subscriptions,
 | 
				
			||||||
 | 
										  rwsem_is_locked(&keyring->sem));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_inc(&key->usage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* there's a matching key we can displace or an empty slot in a newly
 | 
				
			||||||
 | 
						 * allocated list we can fill */
 | 
				
			||||||
 | 
						if (nklist) {
 | 
				
			||||||
 | 
							kdebug("replace %hu/%hu/%hu",
 | 
				
			||||||
 | 
							       nklist->delkey, nklist->nkeys, nklist->maxkeys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							nklist->keys[nklist->delkey] = key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rcu_assign_pointer(keyring->payload.subscriptions, nklist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* dispose of the old keyring list and, if there was one, the
 | 
				
			||||||
 | 
							 * displaced key */
 | 
				
			||||||
 | 
							if (klist) {
 | 
				
			||||||
 | 
								kdebug("dispose %hu/%hu/%hu",
 | 
				
			||||||
 | 
								       klist->delkey, klist->nkeys, klist->maxkeys);
 | 
				
			||||||
 | 
								call_rcu(&klist->rcu, keyring_unlink_rcu_disposal);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* there's sufficient slack space to append directly */
 | 
				
			||||||
 | 
							klist->keys[klist->nkeys] = key;
 | 
				
			||||||
 | 
							smp_wmb();
 | 
				
			||||||
 | 
							klist->nkeys++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * finish linking a key into to a keyring
 | 
				
			||||||
 | 
					 * - must be called with __key_link_begin() having being called
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void __key_link_end(struct key *keyring, struct key_type *type,
 | 
				
			||||||
 | 
							    struct keyring_list *prealloc)
 | 
				
			||||||
 | 
						__releases(&keyring->sem)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						BUG_ON(type == NULL);
 | 
				
			||||||
 | 
						BUG_ON(type->name == NULL);
 | 
				
			||||||
 | 
						kenter("%d,%s,%p", keyring->serial, type->name, prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (type == &key_type_keyring)
 | 
				
			||||||
 | 
							up_write(&keyring_serialise_link_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (prealloc) {
 | 
				
			||||||
 | 
							kfree(prealloc);
 | 
				
			||||||
 | 
							key_payload_reserve(keyring,
 | 
				
			||||||
 | 
									    keyring->datalen - KEYQUOTA_LINK_BYTES);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						up_write(&keyring->sem);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*****************************************************************************/
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * link a key to a keyring
 | 
					 * link a key to a keyring
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int key_link(struct key *keyring, struct key *key)
 | 
					int key_link(struct key *keyring, struct key *key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct keyring_list *prealloc;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key_check(keyring);
 | 
						key_check(keyring);
 | 
				
			||||||
	key_check(key);
 | 
						key_check(key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down_write(&keyring->sem);
 | 
						ret = __key_link_begin(keyring, key->type, key->description, &prealloc);
 | 
				
			||||||
	ret = __key_link(keyring, key);
 | 
						if (ret == 0) {
 | 
				
			||||||
	up_write(&keyring->sem);
 | 
							ret = __key_link_check_live_key(keyring, key);
 | 
				
			||||||
 | 
							if (ret == 0)
 | 
				
			||||||
 | 
								__key_link(keyring, key, &prealloc);
 | 
				
			||||||
 | 
							__key_link_end(keyring, key->type, prealloc);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
} /* end key_link() */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL(key_link);
 | 
					EXPORT_SYMBOL(key_link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -299,6 +299,7 @@ static int construct_alloc_key(struct key_type *type,
 | 
				
			||||||
			       struct key_user *user,
 | 
								       struct key_user *user,
 | 
				
			||||||
			       struct key **_key)
 | 
								       struct key **_key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct keyring_list *prealloc;
 | 
				
			||||||
	const struct cred *cred = current_cred();
 | 
						const struct cred *cred = current_cred();
 | 
				
			||||||
	struct key *key;
 | 
						struct key *key;
 | 
				
			||||||
	key_ref_t key_ref;
 | 
						key_ref_t key_ref;
 | 
				
			||||||
| 
						 | 
					@ -306,6 +307,7 @@ static int construct_alloc_key(struct key_type *type,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kenter("%s,%s,,,", type->name, description);
 | 
						kenter("%s,%s,,,", type->name, description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*_key = NULL;
 | 
				
			||||||
	mutex_lock(&user->cons_lock);
 | 
						mutex_lock(&user->cons_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
 | 
						key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
 | 
				
			||||||
| 
						 | 
					@ -315,8 +317,12 @@ 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) {
 | 
				
			||||||
		down_write(&dest_keyring->sem);
 | 
							ret = __key_link_begin(dest_keyring, type, description,
 | 
				
			||||||
 | 
									       &prealloc);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								goto link_prealloc_failed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* attach the key to the destination keyring under lock, but we do need
 | 
						/* attach the key to the destination keyring under lock, but we do need
 | 
				
			||||||
	 * to do another check just in case someone beat us to it whilst we
 | 
						 * to do another check just in case someone beat us to it whilst we
 | 
				
			||||||
| 
						 | 
					@ -328,11 +334,11 @@ static int construct_alloc_key(struct key_type *type,
 | 
				
			||||||
		goto key_already_present;
 | 
							goto key_already_present;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dest_keyring)
 | 
						if (dest_keyring)
 | 
				
			||||||
		__key_link(dest_keyring, key);
 | 
							__key_link(dest_keyring, key, &prealloc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mutex_unlock(&key_construction_mutex);
 | 
						mutex_unlock(&key_construction_mutex);
 | 
				
			||||||
	if (dest_keyring)
 | 
						if (dest_keyring)
 | 
				
			||||||
		up_write(&dest_keyring->sem);
 | 
							__key_link_end(dest_keyring, type, 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));
 | 
				
			||||||
| 
						 | 
					@ -341,27 +347,36 @@ static int construct_alloc_key(struct key_type *type,
 | 
				
			||||||
	/* the key is now present - we tell the caller that we found it by
 | 
						/* the key is now present - we tell the caller that we found it by
 | 
				
			||||||
	 * returning -EINPROGRESS  */
 | 
						 * returning -EINPROGRESS  */
 | 
				
			||||||
key_already_present:
 | 
					key_already_present:
 | 
				
			||||||
 | 
						key_put(key);
 | 
				
			||||||
	mutex_unlock(&key_construction_mutex);
 | 
						mutex_unlock(&key_construction_mutex);
 | 
				
			||||||
	ret = 0;
 | 
						key = key_ref_to_ptr(key_ref);
 | 
				
			||||||
	if (dest_keyring) {
 | 
						if (dest_keyring) {
 | 
				
			||||||
		ret = __key_link(dest_keyring, key_ref_to_ptr(key_ref));
 | 
							ret = __key_link_check_live_key(dest_keyring, key);
 | 
				
			||||||
		up_write(&dest_keyring->sem);
 | 
							if (ret == 0)
 | 
				
			||||||
 | 
								__key_link(dest_keyring, key, &prealloc);
 | 
				
			||||||
 | 
							__key_link_end(dest_keyring, type, prealloc);
 | 
				
			||||||
 | 
							if (ret < 0)
 | 
				
			||||||
 | 
								goto link_check_failed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	mutex_unlock(&user->cons_lock);
 | 
						mutex_unlock(&user->cons_lock);
 | 
				
			||||||
	key_put(key);
 | 
						*_key = key;
 | 
				
			||||||
	if (ret < 0) {
 | 
					 | 
				
			||||||
		key_ref_put(key_ref);
 | 
					 | 
				
			||||||
		*_key = NULL;
 | 
					 | 
				
			||||||
		kleave(" = %d [link]", ret);
 | 
					 | 
				
			||||||
		return ret;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*_key = key = key_ref_to_ptr(key_ref);
 | 
					 | 
				
			||||||
	kleave(" = -EINPROGRESS [%d]", key_serial(key));
 | 
						kleave(" = -EINPROGRESS [%d]", key_serial(key));
 | 
				
			||||||
	return -EINPROGRESS;
 | 
						return -EINPROGRESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					link_check_failed:
 | 
				
			||||||
 | 
						mutex_unlock(&user->cons_lock);
 | 
				
			||||||
 | 
						key_put(key);
 | 
				
			||||||
 | 
						kleave(" = %d [linkcheck]", ret);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					link_prealloc_failed:
 | 
				
			||||||
 | 
						up_write(&dest_keyring->sem);
 | 
				
			||||||
 | 
						mutex_unlock(&user->cons_lock);
 | 
				
			||||||
 | 
						kleave(" = %d [prelink]", ret);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
alloc_failed:
 | 
					alloc_failed:
 | 
				
			||||||
	mutex_unlock(&user->cons_lock);
 | 
						mutex_unlock(&user->cons_lock);
 | 
				
			||||||
	*_key = NULL;
 | 
					 | 
				
			||||||
	kleave(" = %ld", PTR_ERR(key));
 | 
						kleave(" = %ld", PTR_ERR(key));
 | 
				
			||||||
	return PTR_ERR(key);
 | 
						return PTR_ERR(key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue