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>
diff --git a/security/keys/key.c b/security/keys/key.c
index c70da6f..c1eac80 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -398,7 +398,8 @@
 				      const void *data,
 				      size_t datalen,
 				      struct key *keyring,
-				      struct key *authkey)
+				      struct key *authkey,
+				      struct keyring_list **_prealloc)
 {
 	int ret, awaken;
 
@@ -425,7 +426,7 @@
 
 			/* and link it into the destination keyring */
 			if (keyring)
-				ret = __key_link(keyring, key);
+				__key_link(keyring, key, _prealloc);
 
 			/* disable the authorisation key */
 			if (authkey)
@@ -453,15 +454,21 @@
 			     struct key *keyring,
 			     struct key *authkey)
 {
+	struct keyring_list *prealloc;
 	int ret;
 
-	if (keyring)
-		down_write(&keyring->sem);
+	if (keyring) {
+		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)
-		up_write(&keyring->sem);
+		__key_link_end(keyring, key->type, prealloc);
 
 	return ret;
 
@@ -478,8 +485,9 @@
 			struct key *keyring,
 			struct key *authkey)
 {
+	struct keyring_list *prealloc;
 	struct timespec now;
-	int ret, awaken;
+	int ret, awaken, link_ret = 0;
 
 	key_check(key);
 	key_check(keyring);
@@ -488,7 +496,8 @@
 	ret = -EBUSY;
 
 	if (keyring)
-		down_write(&keyring->sem);
+		link_ret = __key_link_begin(keyring, key->type,
+					    key->description, &prealloc);
 
 	mutex_lock(&key_construction_mutex);
 
@@ -508,8 +517,8 @@
 		ret = 0;
 
 		/* and link it into the destination keyring */
-		if (keyring)
-			ret = __key_link(keyring, key);
+		if (keyring && link_ret == 0)
+			__key_link(keyring, key, &prealloc);
 
 		/* disable the authorisation key */
 		if (authkey)
@@ -519,13 +528,13 @@
 	mutex_unlock(&key_construction_mutex);
 
 	if (keyring)
-		up_write(&keyring->sem);
+		__key_link_end(keyring, key->type, prealloc);
 
 	/* wake up anyone waiting for a key to be constructed */
 	if (awaken)
 		wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
 
-	return ret;
+	return ret == 0 ? link_ret : ret;
 
 } /* end key_negate_and_link() */
 
@@ -749,6 +758,7 @@
 			       key_perm_t perm,
 			       unsigned long flags)
 {
+	struct keyring_list *prealloc;
 	const struct cred *cred = current_cred();
 	struct key_type *ktype;
 	struct key *keyring, *key = NULL;
@@ -775,7 +785,9 @@
 	if (keyring->type != &key_type_keyring)
 		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
 	 * to modify the keyring */
@@ -817,7 +829,8 @@
 	}
 
 	/* 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) {
 		key_put(key);
 		key_ref = ERR_PTR(ret);
@@ -827,7 +840,7 @@
 	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
 
  error_3:
-	up_write(&keyring->sem);
+	__key_link_end(keyring, ktype, prealloc);
  error_2:
 	key_type_put(ktype);
  error:
@@ -837,7 +850,7 @@
 	/* 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
 	 */
-	up_write(&keyring->sem);
+	__key_link_end(keyring, ktype, prealloc);
 	key_type_put(ktype);
 
 	key_ref = __key_update(key_ref, payload, plen);