}
EXPORT_SYMBOL(complete_request_key);
+static int umh_keys_init(struct subprocess_info *info)
+{
+ struct cred *cred = (struct cred*)current_cred();
+ struct key *keyring = info->data;
+ /*
+ * This is called in context of freshly forked kthread before
+ * kernel_execve(), we can just change our ->session_keyring.
+ */
+ return install_session_keyring_to_cred(cred, keyring);
+}
+
+static void umh_keys_cleanup(struct subprocess_info *info)
+{
+ struct key *keyring = info->data;
+ key_put(keyring);
+}
+
+static int call_usermodehelper_keys(char *path, char **argv, char **envp,
+ struct key *session_keyring, enum umh_wait wait)
+{
+ gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
+ struct subprocess_info *info =
+ call_usermodehelper_setup(path, argv, envp, gfp_mask);
+
+ if (!info)
+ return -ENOMEM;
+
+ call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup,
+ key_get(session_keyring));
+ return call_usermodehelper_exec(info, wait);
+}
+
/*
* request userspace finish the construction of a key
* - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
}
/* attach the auth key to the session keyring */
- ret = __key_link(keyring, authkey);
+ ret = key_link(keyring, authkey);
if (ret < 0)
goto error_link;
struct key_user *user,
struct key **_key)
{
+ struct keyring_list *prealloc;
const struct cred *cred = current_cred();
struct key *key;
key_ref_t key_ref;
kenter("%s,%s,,,", type->name, description);
+ *_key = NULL;
mutex_lock(&user->cons_lock);
key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred,
set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
- if (dest_keyring)
- down_write(&dest_keyring->sem);
+ if (dest_keyring) {
+ 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
* to do another check just in case someone beat us to it whilst we
goto key_already_present;
if (dest_keyring)
- __key_link(dest_keyring, key);
+ __key_link(dest_keyring, key, &prealloc);
mutex_unlock(&key_construction_mutex);
if (dest_keyring)
- up_write(&dest_keyring->sem);
+ __key_link_end(dest_keyring, type, prealloc);
mutex_unlock(&user->cons_lock);
*_key = key;
kleave(" = 0 [%d]", key_serial(key));
/* the key is now present - we tell the caller that we found it by
* returning -EINPROGRESS */
key_already_present:
+ key_put(key);
mutex_unlock(&key_construction_mutex);
- ret = 0;
+ key = key_ref_to_ptr(key_ref);
if (dest_keyring) {
- ret = __key_link(dest_keyring, key_ref_to_ptr(key_ref));
- up_write(&dest_keyring->sem);
+ 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);
+ if (ret < 0)
+ goto link_check_failed;
}
mutex_unlock(&user->cons_lock);
- key_put(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);
+ *_key = key;
kleave(" = -EINPROGRESS [%d]", key_serial(key));
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:
mutex_unlock(&user->cons_lock);
- *_key = NULL;
kleave(" = %ld", PTR_ERR(key));
return PTR_ERR(key);
}