162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* Request a key from userspace
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * See Documentation/security/keys/request-key.rst
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/export.h>
1162306a36Sopenharmony_ci#include <linux/sched.h>
1262306a36Sopenharmony_ci#include <linux/kmod.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/keyctl.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <net/net_namespace.h>
1762306a36Sopenharmony_ci#include "internal.h"
1862306a36Sopenharmony_ci#include <keys/request_key_auth-type.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define key_negative_timeout	60	/* default timeout on a negative key's existence */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic struct key *check_cached_key(struct keyring_search_context *ctx)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci#ifdef CONFIG_KEYS_REQUEST_CACHE
2562306a36Sopenharmony_ci	struct key *key = current->cached_requested_key;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (key &&
2862306a36Sopenharmony_ci	    ctx->match_data.cmp(key, &ctx->match_data) &&
2962306a36Sopenharmony_ci	    !(key->flags & ((1 << KEY_FLAG_INVALIDATED) |
3062306a36Sopenharmony_ci			    (1 << KEY_FLAG_REVOKED))))
3162306a36Sopenharmony_ci		return key_get(key);
3262306a36Sopenharmony_ci#endif
3362306a36Sopenharmony_ci	return NULL;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void cache_requested_key(struct key *key)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci#ifdef CONFIG_KEYS_REQUEST_CACHE
3962306a36Sopenharmony_ci	struct task_struct *t = current;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/* Do not cache key if it is a kernel thread */
4262306a36Sopenharmony_ci	if (!(t->flags & PF_KTHREAD)) {
4362306a36Sopenharmony_ci		key_put(t->cached_requested_key);
4462306a36Sopenharmony_ci		t->cached_requested_key = key_get(key);
4562306a36Sopenharmony_ci		set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
4662306a36Sopenharmony_ci	}
4762306a36Sopenharmony_ci#endif
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/**
5162306a36Sopenharmony_ci * complete_request_key - Complete the construction of a key.
5262306a36Sopenharmony_ci * @authkey: The authorisation key.
5362306a36Sopenharmony_ci * @error: The success or failute of the construction.
5462306a36Sopenharmony_ci *
5562306a36Sopenharmony_ci * Complete the attempt to construct a key.  The key will be negated
5662306a36Sopenharmony_ci * if an error is indicated.  The authorisation key will be revoked
5762306a36Sopenharmony_ci * unconditionally.
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_civoid complete_request_key(struct key *authkey, int error)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct request_key_auth *rka = get_request_key_auth(authkey);
6262306a36Sopenharmony_ci	struct key *key = rka->target_key;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	kenter("%d{%d},%d", authkey->serial, key->serial, error);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	if (error < 0)
6762306a36Sopenharmony_ci		key_negate_and_link(key, key_negative_timeout, NULL, authkey);
6862306a36Sopenharmony_ci	else
6962306a36Sopenharmony_ci		key_revoke(authkey);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ciEXPORT_SYMBOL(complete_request_key);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci/*
7462306a36Sopenharmony_ci * Initialise a usermode helper that is going to have a specific session
7562306a36Sopenharmony_ci * keyring.
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * This is called in context of freshly forked kthread before kernel_execve(),
7862306a36Sopenharmony_ci * so we can simply install the desired session_keyring at this point.
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_cistatic int umh_keys_init(struct subprocess_info *info, struct cred *cred)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct key *keyring = info->data;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return install_session_keyring_to_cred(cred, keyring);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/*
8862306a36Sopenharmony_ci * Clean up a usermode helper with session keyring.
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cistatic void umh_keys_cleanup(struct subprocess_info *info)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct key *keyring = info->data;
9362306a36Sopenharmony_ci	key_put(keyring);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Call a usermode helper with a specific session keyring.
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_cistatic int call_usermodehelper_keys(const char *path, char **argv, char **envp,
10062306a36Sopenharmony_ci					struct key *session_keyring, int wait)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct subprocess_info *info;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL,
10562306a36Sopenharmony_ci					  umh_keys_init, umh_keys_cleanup,
10662306a36Sopenharmony_ci					  session_keyring);
10762306a36Sopenharmony_ci	if (!info)
10862306a36Sopenharmony_ci		return -ENOMEM;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	key_get(session_keyring);
11162306a36Sopenharmony_ci	return call_usermodehelper_exec(info, wait);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*
11562306a36Sopenharmony_ci * Request userspace finish the construction of a key
11662306a36Sopenharmony_ci * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
11762306a36Sopenharmony_ci */
11862306a36Sopenharmony_cistatic int call_sbin_request_key(struct key *authkey, void *aux)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	static char const request_key[] = "/sbin/request-key";
12162306a36Sopenharmony_ci	struct request_key_auth *rka = get_request_key_auth(authkey);
12262306a36Sopenharmony_ci	const struct cred *cred = current_cred();
12362306a36Sopenharmony_ci	key_serial_t prkey, sskey;
12462306a36Sopenharmony_ci	struct key *key = rka->target_key, *keyring, *session, *user_session;
12562306a36Sopenharmony_ci	char *argv[9], *envp[3], uid_str[12], gid_str[12];
12662306a36Sopenharmony_ci	char key_str[12], keyring_str[3][12];
12762306a36Sopenharmony_ci	char desc[20];
12862306a36Sopenharmony_ci	int ret, i;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	ret = look_up_user_keyrings(NULL, &user_session);
13362306a36Sopenharmony_ci	if (ret < 0)
13462306a36Sopenharmony_ci		goto error_us;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* allocate a new session keyring */
13762306a36Sopenharmony_ci	sprintf(desc, "_req.%u", key->serial);
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	cred = get_current_cred();
14062306a36Sopenharmony_ci	keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
14162306a36Sopenharmony_ci				KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
14262306a36Sopenharmony_ci				KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
14362306a36Sopenharmony_ci	put_cred(cred);
14462306a36Sopenharmony_ci	if (IS_ERR(keyring)) {
14562306a36Sopenharmony_ci		ret = PTR_ERR(keyring);
14662306a36Sopenharmony_ci		goto error_alloc;
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* attach the auth key to the session keyring */
15062306a36Sopenharmony_ci	ret = key_link(keyring, authkey);
15162306a36Sopenharmony_ci	if (ret < 0)
15262306a36Sopenharmony_ci		goto error_link;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* record the UID and GID */
15562306a36Sopenharmony_ci	sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid));
15662306a36Sopenharmony_ci	sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid));
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	/* we say which key is under construction */
15962306a36Sopenharmony_ci	sprintf(key_str, "%d", key->serial);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* we specify the process's default keyrings */
16262306a36Sopenharmony_ci	sprintf(keyring_str[0], "%d",
16362306a36Sopenharmony_ci		cred->thread_keyring ? cred->thread_keyring->serial : 0);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	prkey = 0;
16662306a36Sopenharmony_ci	if (cred->process_keyring)
16762306a36Sopenharmony_ci		prkey = cred->process_keyring->serial;
16862306a36Sopenharmony_ci	sprintf(keyring_str[1], "%d", prkey);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	session = cred->session_keyring;
17162306a36Sopenharmony_ci	if (!session)
17262306a36Sopenharmony_ci		session = user_session;
17362306a36Sopenharmony_ci	sskey = session->serial;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	sprintf(keyring_str[2], "%d", sskey);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* set up a minimal environment */
17862306a36Sopenharmony_ci	i = 0;
17962306a36Sopenharmony_ci	envp[i++] = "HOME=/";
18062306a36Sopenharmony_ci	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
18162306a36Sopenharmony_ci	envp[i] = NULL;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	/* set up the argument list */
18462306a36Sopenharmony_ci	i = 0;
18562306a36Sopenharmony_ci	argv[i++] = (char *)request_key;
18662306a36Sopenharmony_ci	argv[i++] = (char *)rka->op;
18762306a36Sopenharmony_ci	argv[i++] = key_str;
18862306a36Sopenharmony_ci	argv[i++] = uid_str;
18962306a36Sopenharmony_ci	argv[i++] = gid_str;
19062306a36Sopenharmony_ci	argv[i++] = keyring_str[0];
19162306a36Sopenharmony_ci	argv[i++] = keyring_str[1];
19262306a36Sopenharmony_ci	argv[i++] = keyring_str[2];
19362306a36Sopenharmony_ci	argv[i] = NULL;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	/* do it */
19662306a36Sopenharmony_ci	ret = call_usermodehelper_keys(request_key, argv, envp, keyring,
19762306a36Sopenharmony_ci				       UMH_WAIT_PROC);
19862306a36Sopenharmony_ci	kdebug("usermode -> 0x%x", ret);
19962306a36Sopenharmony_ci	if (ret >= 0) {
20062306a36Sopenharmony_ci		/* ret is the exit/wait code */
20162306a36Sopenharmony_ci		if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) ||
20262306a36Sopenharmony_ci		    key_validate(key) < 0)
20362306a36Sopenharmony_ci			ret = -ENOKEY;
20462306a36Sopenharmony_ci		else
20562306a36Sopenharmony_ci			/* ignore any errors from userspace if the key was
20662306a36Sopenharmony_ci			 * instantiated */
20762306a36Sopenharmony_ci			ret = 0;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cierror_link:
21162306a36Sopenharmony_ci	key_put(keyring);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cierror_alloc:
21462306a36Sopenharmony_ci	key_put(user_session);
21562306a36Sopenharmony_cierror_us:
21662306a36Sopenharmony_ci	complete_request_key(authkey, ret);
21762306a36Sopenharmony_ci	kleave(" = %d", ret);
21862306a36Sopenharmony_ci	return ret;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci/*
22262306a36Sopenharmony_ci * Call out to userspace for key construction.
22362306a36Sopenharmony_ci *
22462306a36Sopenharmony_ci * Program failure is ignored in favour of key status.
22562306a36Sopenharmony_ci */
22662306a36Sopenharmony_cistatic int construct_key(struct key *key, const void *callout_info,
22762306a36Sopenharmony_ci			 size_t callout_len, void *aux,
22862306a36Sopenharmony_ci			 struct key *dest_keyring)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	request_key_actor_t actor;
23162306a36Sopenharmony_ci	struct key *authkey;
23262306a36Sopenharmony_ci	int ret;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* allocate an authorisation key */
23762306a36Sopenharmony_ci	authkey = request_key_auth_new(key, "create", callout_info, callout_len,
23862306a36Sopenharmony_ci				       dest_keyring);
23962306a36Sopenharmony_ci	if (IS_ERR(authkey))
24062306a36Sopenharmony_ci		return PTR_ERR(authkey);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	/* Make the call */
24362306a36Sopenharmony_ci	actor = call_sbin_request_key;
24462306a36Sopenharmony_ci	if (key->type->request_key)
24562306a36Sopenharmony_ci		actor = key->type->request_key;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	ret = actor(authkey, aux);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* check that the actor called complete_request_key() prior to
25062306a36Sopenharmony_ci	 * returning an error */
25162306a36Sopenharmony_ci	WARN_ON(ret < 0 &&
25262306a36Sopenharmony_ci		!test_bit(KEY_FLAG_INVALIDATED, &authkey->flags));
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	key_put(authkey);
25562306a36Sopenharmony_ci	kleave(" = %d", ret);
25662306a36Sopenharmony_ci	return ret;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/*
26062306a36Sopenharmony_ci * Get the appropriate destination keyring for the request.
26162306a36Sopenharmony_ci *
26262306a36Sopenharmony_ci * The keyring selected is returned with an extra reference upon it which the
26362306a36Sopenharmony_ci * caller must release.
26462306a36Sopenharmony_ci */
26562306a36Sopenharmony_cistatic int construct_get_dest_keyring(struct key **_dest_keyring)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct request_key_auth *rka;
26862306a36Sopenharmony_ci	const struct cred *cred = current_cred();
26962306a36Sopenharmony_ci	struct key *dest_keyring = *_dest_keyring, *authkey;
27062306a36Sopenharmony_ci	int ret;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	kenter("%p", dest_keyring);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* find the appropriate keyring */
27562306a36Sopenharmony_ci	if (dest_keyring) {
27662306a36Sopenharmony_ci		/* the caller supplied one */
27762306a36Sopenharmony_ci		key_get(dest_keyring);
27862306a36Sopenharmony_ci	} else {
27962306a36Sopenharmony_ci		bool do_perm_check = true;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		/* use a default keyring; falling through the cases until we
28262306a36Sopenharmony_ci		 * find one that we actually have */
28362306a36Sopenharmony_ci		switch (cred->jit_keyring) {
28462306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_DEFAULT:
28562306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
28662306a36Sopenharmony_ci			if (cred->request_key_auth) {
28762306a36Sopenharmony_ci				authkey = cred->request_key_auth;
28862306a36Sopenharmony_ci				down_read(&authkey->sem);
28962306a36Sopenharmony_ci				rka = get_request_key_auth(authkey);
29062306a36Sopenharmony_ci				if (!test_bit(KEY_FLAG_REVOKED,
29162306a36Sopenharmony_ci					      &authkey->flags))
29262306a36Sopenharmony_ci					dest_keyring =
29362306a36Sopenharmony_ci						key_get(rka->dest_keyring);
29462306a36Sopenharmony_ci				up_read(&authkey->sem);
29562306a36Sopenharmony_ci				if (dest_keyring) {
29662306a36Sopenharmony_ci					do_perm_check = false;
29762306a36Sopenharmony_ci					break;
29862306a36Sopenharmony_ci				}
29962306a36Sopenharmony_ci			}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci			fallthrough;
30262306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_THREAD_KEYRING:
30362306a36Sopenharmony_ci			dest_keyring = key_get(cred->thread_keyring);
30462306a36Sopenharmony_ci			if (dest_keyring)
30562306a36Sopenharmony_ci				break;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci			fallthrough;
30862306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_PROCESS_KEYRING:
30962306a36Sopenharmony_ci			dest_keyring = key_get(cred->process_keyring);
31062306a36Sopenharmony_ci			if (dest_keyring)
31162306a36Sopenharmony_ci				break;
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci			fallthrough;
31462306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_SESSION_KEYRING:
31562306a36Sopenharmony_ci			dest_keyring = key_get(cred->session_keyring);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci			if (dest_keyring)
31862306a36Sopenharmony_ci				break;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci			fallthrough;
32162306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
32262306a36Sopenharmony_ci			ret = look_up_user_keyrings(NULL, &dest_keyring);
32362306a36Sopenharmony_ci			if (ret < 0)
32462306a36Sopenharmony_ci				return ret;
32562306a36Sopenharmony_ci			break;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_USER_KEYRING:
32862306a36Sopenharmony_ci			ret = look_up_user_keyrings(&dest_keyring, NULL);
32962306a36Sopenharmony_ci			if (ret < 0)
33062306a36Sopenharmony_ci				return ret;
33162306a36Sopenharmony_ci			break;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		case KEY_REQKEY_DEFL_GROUP_KEYRING:
33462306a36Sopenharmony_ci		default:
33562306a36Sopenharmony_ci			BUG();
33662306a36Sopenharmony_ci		}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci		/*
33962306a36Sopenharmony_ci		 * Require Write permission on the keyring.  This is essential
34062306a36Sopenharmony_ci		 * because the default keyring may be the session keyring, and
34162306a36Sopenharmony_ci		 * joining a keyring only requires Search permission.
34262306a36Sopenharmony_ci		 *
34362306a36Sopenharmony_ci		 * However, this check is skipped for the "requestor keyring" so
34462306a36Sopenharmony_ci		 * that /sbin/request-key can itself use request_key() to add
34562306a36Sopenharmony_ci		 * keys to the original requestor's destination keyring.
34662306a36Sopenharmony_ci		 */
34762306a36Sopenharmony_ci		if (dest_keyring && do_perm_check) {
34862306a36Sopenharmony_ci			ret = key_permission(make_key_ref(dest_keyring, 1),
34962306a36Sopenharmony_ci					     KEY_NEED_WRITE);
35062306a36Sopenharmony_ci			if (ret) {
35162306a36Sopenharmony_ci				key_put(dest_keyring);
35262306a36Sopenharmony_ci				return ret;
35362306a36Sopenharmony_ci			}
35462306a36Sopenharmony_ci		}
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	*_dest_keyring = dest_keyring;
35862306a36Sopenharmony_ci	kleave(" [dk %d]", key_serial(dest_keyring));
35962306a36Sopenharmony_ci	return 0;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/*
36362306a36Sopenharmony_ci * Allocate a new key in under-construction state and attempt to link it in to
36462306a36Sopenharmony_ci * the requested keyring.
36562306a36Sopenharmony_ci *
36662306a36Sopenharmony_ci * May return a key that's already under construction instead if there was a
36762306a36Sopenharmony_ci * race between two thread calling request_key().
36862306a36Sopenharmony_ci */
36962306a36Sopenharmony_cistatic int construct_alloc_key(struct keyring_search_context *ctx,
37062306a36Sopenharmony_ci			       struct key *dest_keyring,
37162306a36Sopenharmony_ci			       unsigned long flags,
37262306a36Sopenharmony_ci			       struct key_user *user,
37362306a36Sopenharmony_ci			       struct key **_key)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct assoc_array_edit *edit = NULL;
37662306a36Sopenharmony_ci	struct key *key;
37762306a36Sopenharmony_ci	key_perm_t perm;
37862306a36Sopenharmony_ci	key_ref_t key_ref;
37962306a36Sopenharmony_ci	int ret;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	kenter("%s,%s,,,",
38262306a36Sopenharmony_ci	       ctx->index_key.type->name, ctx->index_key.description);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	*_key = NULL;
38562306a36Sopenharmony_ci	mutex_lock(&user->cons_lock);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
38862306a36Sopenharmony_ci	perm |= KEY_USR_VIEW;
38962306a36Sopenharmony_ci	if (ctx->index_key.type->read)
39062306a36Sopenharmony_ci		perm |= KEY_POS_READ;
39162306a36Sopenharmony_ci	if (ctx->index_key.type == &key_type_keyring ||
39262306a36Sopenharmony_ci	    ctx->index_key.type->update)
39362306a36Sopenharmony_ci		perm |= KEY_POS_WRITE;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	key = key_alloc(ctx->index_key.type, ctx->index_key.description,
39662306a36Sopenharmony_ci			ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
39762306a36Sopenharmony_ci			perm, flags, NULL);
39862306a36Sopenharmony_ci	if (IS_ERR(key))
39962306a36Sopenharmony_ci		goto alloc_failed;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (dest_keyring) {
40462306a36Sopenharmony_ci		ret = __key_link_lock(dest_keyring, &key->index_key);
40562306a36Sopenharmony_ci		if (ret < 0)
40662306a36Sopenharmony_ci			goto link_lock_failed;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Attach the key to the destination keyring under lock, but we do need
41162306a36Sopenharmony_ci	 * to do another check just in case someone beat us to it whilst we
41262306a36Sopenharmony_ci	 * waited for locks.
41362306a36Sopenharmony_ci	 *
41462306a36Sopenharmony_ci	 * The caller might specify a comparison function which looks for keys
41562306a36Sopenharmony_ci	 * that do not exactly match but are still equivalent from the caller's
41662306a36Sopenharmony_ci	 * perspective. The __key_link_begin() operation must be done only after
41762306a36Sopenharmony_ci	 * an actual key is determined.
41862306a36Sopenharmony_ci	 */
41962306a36Sopenharmony_ci	mutex_lock(&key_construction_mutex);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	rcu_read_lock();
42262306a36Sopenharmony_ci	key_ref = search_process_keyrings_rcu(ctx);
42362306a36Sopenharmony_ci	rcu_read_unlock();
42462306a36Sopenharmony_ci	if (!IS_ERR(key_ref))
42562306a36Sopenharmony_ci		goto key_already_present;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (dest_keyring) {
42862306a36Sopenharmony_ci		ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
42962306a36Sopenharmony_ci		if (ret < 0)
43062306a36Sopenharmony_ci			goto link_alloc_failed;
43162306a36Sopenharmony_ci		__key_link(dest_keyring, key, &edit);
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	mutex_unlock(&key_construction_mutex);
43562306a36Sopenharmony_ci	if (dest_keyring)
43662306a36Sopenharmony_ci		__key_link_end(dest_keyring, &key->index_key, edit);
43762306a36Sopenharmony_ci	mutex_unlock(&user->cons_lock);
43862306a36Sopenharmony_ci	*_key = key;
43962306a36Sopenharmony_ci	kleave(" = 0 [%d]", key_serial(key));
44062306a36Sopenharmony_ci	return 0;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	/* the key is now present - we tell the caller that we found it by
44362306a36Sopenharmony_ci	 * returning -EINPROGRESS  */
44462306a36Sopenharmony_cikey_already_present:
44562306a36Sopenharmony_ci	key_put(key);
44662306a36Sopenharmony_ci	mutex_unlock(&key_construction_mutex);
44762306a36Sopenharmony_ci	key = key_ref_to_ptr(key_ref);
44862306a36Sopenharmony_ci	if (dest_keyring) {
44962306a36Sopenharmony_ci		ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
45062306a36Sopenharmony_ci		if (ret < 0)
45162306a36Sopenharmony_ci			goto link_alloc_failed_unlocked;
45262306a36Sopenharmony_ci		ret = __key_link_check_live_key(dest_keyring, key);
45362306a36Sopenharmony_ci		if (ret == 0)
45462306a36Sopenharmony_ci			__key_link(dest_keyring, key, &edit);
45562306a36Sopenharmony_ci		__key_link_end(dest_keyring, &key->index_key, edit);
45662306a36Sopenharmony_ci		if (ret < 0)
45762306a36Sopenharmony_ci			goto link_check_failed;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	mutex_unlock(&user->cons_lock);
46062306a36Sopenharmony_ci	*_key = key;
46162306a36Sopenharmony_ci	kleave(" = -EINPROGRESS [%d]", key_serial(key));
46262306a36Sopenharmony_ci	return -EINPROGRESS;
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_cilink_check_failed:
46562306a36Sopenharmony_ci	mutex_unlock(&user->cons_lock);
46662306a36Sopenharmony_ci	key_put(key);
46762306a36Sopenharmony_ci	kleave(" = %d [linkcheck]", ret);
46862306a36Sopenharmony_ci	return ret;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cilink_alloc_failed:
47162306a36Sopenharmony_ci	mutex_unlock(&key_construction_mutex);
47262306a36Sopenharmony_cilink_alloc_failed_unlocked:
47362306a36Sopenharmony_ci	__key_link_end(dest_keyring, &key->index_key, edit);
47462306a36Sopenharmony_cilink_lock_failed:
47562306a36Sopenharmony_ci	mutex_unlock(&user->cons_lock);
47662306a36Sopenharmony_ci	key_put(key);
47762306a36Sopenharmony_ci	kleave(" = %d [prelink]", ret);
47862306a36Sopenharmony_ci	return ret;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cialloc_failed:
48162306a36Sopenharmony_ci	mutex_unlock(&user->cons_lock);
48262306a36Sopenharmony_ci	kleave(" = %ld", PTR_ERR(key));
48362306a36Sopenharmony_ci	return PTR_ERR(key);
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci/*
48762306a36Sopenharmony_ci * Commence key construction.
48862306a36Sopenharmony_ci */
48962306a36Sopenharmony_cistatic struct key *construct_key_and_link(struct keyring_search_context *ctx,
49062306a36Sopenharmony_ci					  const char *callout_info,
49162306a36Sopenharmony_ci					  size_t callout_len,
49262306a36Sopenharmony_ci					  void *aux,
49362306a36Sopenharmony_ci					  struct key *dest_keyring,
49462306a36Sopenharmony_ci					  unsigned long flags)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct key_user *user;
49762306a36Sopenharmony_ci	struct key *key;
49862306a36Sopenharmony_ci	int ret;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	kenter("");
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (ctx->index_key.type == &key_type_keyring)
50362306a36Sopenharmony_ci		return ERR_PTR(-EPERM);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	ret = construct_get_dest_keyring(&dest_keyring);
50662306a36Sopenharmony_ci	if (ret)
50762306a36Sopenharmony_ci		goto error;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	user = key_user_lookup(current_fsuid());
51062306a36Sopenharmony_ci	if (!user) {
51162306a36Sopenharmony_ci		ret = -ENOMEM;
51262306a36Sopenharmony_ci		goto error_put_dest_keyring;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key);
51662306a36Sopenharmony_ci	key_user_put(user);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (ret == 0) {
51962306a36Sopenharmony_ci		ret = construct_key(key, callout_info, callout_len, aux,
52062306a36Sopenharmony_ci				    dest_keyring);
52162306a36Sopenharmony_ci		if (ret < 0) {
52262306a36Sopenharmony_ci			kdebug("cons failed");
52362306a36Sopenharmony_ci			goto construction_failed;
52462306a36Sopenharmony_ci		}
52562306a36Sopenharmony_ci	} else if (ret == -EINPROGRESS) {
52662306a36Sopenharmony_ci		ret = 0;
52762306a36Sopenharmony_ci	} else {
52862306a36Sopenharmony_ci		goto error_put_dest_keyring;
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	key_put(dest_keyring);
53262306a36Sopenharmony_ci	kleave(" = key %d", key_serial(key));
53362306a36Sopenharmony_ci	return key;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ciconstruction_failed:
53662306a36Sopenharmony_ci	key_negate_and_link(key, key_negative_timeout, NULL, NULL);
53762306a36Sopenharmony_ci	key_put(key);
53862306a36Sopenharmony_cierror_put_dest_keyring:
53962306a36Sopenharmony_ci	key_put(dest_keyring);
54062306a36Sopenharmony_cierror:
54162306a36Sopenharmony_ci	kleave(" = %d", ret);
54262306a36Sopenharmony_ci	return ERR_PTR(ret);
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci/**
54662306a36Sopenharmony_ci * request_key_and_link - Request a key and cache it in a keyring.
54762306a36Sopenharmony_ci * @type: The type of key we want.
54862306a36Sopenharmony_ci * @description: The searchable description of the key.
54962306a36Sopenharmony_ci * @domain_tag: The domain in which the key operates.
55062306a36Sopenharmony_ci * @callout_info: The data to pass to the instantiation upcall (or NULL).
55162306a36Sopenharmony_ci * @callout_len: The length of callout_info.
55262306a36Sopenharmony_ci * @aux: Auxiliary data for the upcall.
55362306a36Sopenharmony_ci * @dest_keyring: Where to cache the key.
55462306a36Sopenharmony_ci * @flags: Flags to key_alloc().
55562306a36Sopenharmony_ci *
55662306a36Sopenharmony_ci * A key matching the specified criteria (type, description, domain_tag) is
55762306a36Sopenharmony_ci * searched for in the process's keyrings and returned with its usage count
55862306a36Sopenharmony_ci * incremented if found.  Otherwise, if callout_info is not NULL, a key will be
55962306a36Sopenharmony_ci * allocated and some service (probably in userspace) will be asked to
56062306a36Sopenharmony_ci * instantiate it.
56162306a36Sopenharmony_ci *
56262306a36Sopenharmony_ci * If successfully found or created, the key will be linked to the destination
56362306a36Sopenharmony_ci * keyring if one is provided.
56462306a36Sopenharmony_ci *
56562306a36Sopenharmony_ci * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED
56662306a36Sopenharmony_ci * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was
56762306a36Sopenharmony_ci * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT
56862306a36Sopenharmony_ci * if insufficient key quota was available to create a new key; or -ENOMEM if
56962306a36Sopenharmony_ci * insufficient memory was available.
57062306a36Sopenharmony_ci *
57162306a36Sopenharmony_ci * If the returned key was created, then it may still be under construction,
57262306a36Sopenharmony_ci * and wait_for_key_construction() should be used to wait for that to complete.
57362306a36Sopenharmony_ci */
57462306a36Sopenharmony_cistruct key *request_key_and_link(struct key_type *type,
57562306a36Sopenharmony_ci				 const char *description,
57662306a36Sopenharmony_ci				 struct key_tag *domain_tag,
57762306a36Sopenharmony_ci				 const void *callout_info,
57862306a36Sopenharmony_ci				 size_t callout_len,
57962306a36Sopenharmony_ci				 void *aux,
58062306a36Sopenharmony_ci				 struct key *dest_keyring,
58162306a36Sopenharmony_ci				 unsigned long flags)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct keyring_search_context ctx = {
58462306a36Sopenharmony_ci		.index_key.type		= type,
58562306a36Sopenharmony_ci		.index_key.domain_tag	= domain_tag,
58662306a36Sopenharmony_ci		.index_key.description	= description,
58762306a36Sopenharmony_ci		.index_key.desc_len	= strlen(description),
58862306a36Sopenharmony_ci		.cred			= current_cred(),
58962306a36Sopenharmony_ci		.match_data.cmp		= key_default_cmp,
59062306a36Sopenharmony_ci		.match_data.raw_data	= description,
59162306a36Sopenharmony_ci		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
59262306a36Sopenharmony_ci		.flags			= (KEYRING_SEARCH_DO_STATE_CHECK |
59362306a36Sopenharmony_ci					   KEYRING_SEARCH_SKIP_EXPIRED |
59462306a36Sopenharmony_ci					   KEYRING_SEARCH_RECURSE),
59562306a36Sopenharmony_ci	};
59662306a36Sopenharmony_ci	struct key *key;
59762306a36Sopenharmony_ci	key_ref_t key_ref;
59862306a36Sopenharmony_ci	int ret;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	kenter("%s,%s,%p,%zu,%p,%p,%lx",
60162306a36Sopenharmony_ci	       ctx.index_key.type->name, ctx.index_key.description,
60262306a36Sopenharmony_ci	       callout_info, callout_len, aux, dest_keyring, flags);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (type->match_preparse) {
60562306a36Sopenharmony_ci		ret = type->match_preparse(&ctx.match_data);
60662306a36Sopenharmony_ci		if (ret < 0) {
60762306a36Sopenharmony_ci			key = ERR_PTR(ret);
60862306a36Sopenharmony_ci			goto error;
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	key = check_cached_key(&ctx);
61362306a36Sopenharmony_ci	if (key)
61462306a36Sopenharmony_ci		goto error_free;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* search all the process keyrings for a key */
61762306a36Sopenharmony_ci	rcu_read_lock();
61862306a36Sopenharmony_ci	key_ref = search_process_keyrings_rcu(&ctx);
61962306a36Sopenharmony_ci	rcu_read_unlock();
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	if (!IS_ERR(key_ref)) {
62262306a36Sopenharmony_ci		if (dest_keyring) {
62362306a36Sopenharmony_ci			ret = key_task_permission(key_ref, current_cred(),
62462306a36Sopenharmony_ci						  KEY_NEED_LINK);
62562306a36Sopenharmony_ci			if (ret < 0) {
62662306a36Sopenharmony_ci				key_ref_put(key_ref);
62762306a36Sopenharmony_ci				key = ERR_PTR(ret);
62862306a36Sopenharmony_ci				goto error_free;
62962306a36Sopenharmony_ci			}
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		key = key_ref_to_ptr(key_ref);
63362306a36Sopenharmony_ci		if (dest_keyring) {
63462306a36Sopenharmony_ci			ret = key_link(dest_keyring, key);
63562306a36Sopenharmony_ci			if (ret < 0) {
63662306a36Sopenharmony_ci				key_put(key);
63762306a36Sopenharmony_ci				key = ERR_PTR(ret);
63862306a36Sopenharmony_ci				goto error_free;
63962306a36Sopenharmony_ci			}
64062306a36Sopenharmony_ci		}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci		/* Only cache the key on immediate success */
64362306a36Sopenharmony_ci		cache_requested_key(key);
64462306a36Sopenharmony_ci	} else if (PTR_ERR(key_ref) != -EAGAIN) {
64562306a36Sopenharmony_ci		key = ERR_CAST(key_ref);
64662306a36Sopenharmony_ci	} else  {
64762306a36Sopenharmony_ci		/* the search failed, but the keyrings were searchable, so we
64862306a36Sopenharmony_ci		 * should consult userspace if we can */
64962306a36Sopenharmony_ci		key = ERR_PTR(-ENOKEY);
65062306a36Sopenharmony_ci		if (!callout_info)
65162306a36Sopenharmony_ci			goto error_free;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci		key = construct_key_and_link(&ctx, callout_info, callout_len,
65462306a36Sopenharmony_ci					     aux, dest_keyring, flags);
65562306a36Sopenharmony_ci	}
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cierror_free:
65862306a36Sopenharmony_ci	if (type->match_free)
65962306a36Sopenharmony_ci		type->match_free(&ctx.match_data);
66062306a36Sopenharmony_cierror:
66162306a36Sopenharmony_ci	kleave(" = %p", key);
66262306a36Sopenharmony_ci	return key;
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci/**
66662306a36Sopenharmony_ci * wait_for_key_construction - Wait for construction of a key to complete
66762306a36Sopenharmony_ci * @key: The key being waited for.
66862306a36Sopenharmony_ci * @intr: Whether to wait interruptibly.
66962306a36Sopenharmony_ci *
67062306a36Sopenharmony_ci * Wait for a key to finish being constructed.
67162306a36Sopenharmony_ci *
67262306a36Sopenharmony_ci * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY
67362306a36Sopenharmony_ci * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was
67462306a36Sopenharmony_ci * revoked or expired.
67562306a36Sopenharmony_ci */
67662306a36Sopenharmony_ciint wait_for_key_construction(struct key *key, bool intr)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	int ret;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT,
68162306a36Sopenharmony_ci			  intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
68262306a36Sopenharmony_ci	if (ret)
68362306a36Sopenharmony_ci		return -ERESTARTSYS;
68462306a36Sopenharmony_ci	ret = key_read_state(key);
68562306a36Sopenharmony_ci	if (ret < 0)
68662306a36Sopenharmony_ci		return ret;
68762306a36Sopenharmony_ci	return key_validate(key);
68862306a36Sopenharmony_ci}
68962306a36Sopenharmony_ciEXPORT_SYMBOL(wait_for_key_construction);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci/**
69262306a36Sopenharmony_ci * request_key_tag - Request a key and wait for construction
69362306a36Sopenharmony_ci * @type: Type of key.
69462306a36Sopenharmony_ci * @description: The searchable description of the key.
69562306a36Sopenharmony_ci * @domain_tag: The domain in which the key operates.
69662306a36Sopenharmony_ci * @callout_info: The data to pass to the instantiation upcall (or NULL).
69762306a36Sopenharmony_ci *
69862306a36Sopenharmony_ci * As for request_key_and_link() except that it does not add the returned key
69962306a36Sopenharmony_ci * to a keyring if found, new keys are always allocated in the user's quota,
70062306a36Sopenharmony_ci * the callout_info must be a NUL-terminated string and no auxiliary data can
70162306a36Sopenharmony_ci * be passed.
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * Furthermore, it then works as wait_for_key_construction() to wait for the
70462306a36Sopenharmony_ci * completion of keys undergoing construction with a non-interruptible wait.
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_cistruct key *request_key_tag(struct key_type *type,
70762306a36Sopenharmony_ci			    const char *description,
70862306a36Sopenharmony_ci			    struct key_tag *domain_tag,
70962306a36Sopenharmony_ci			    const char *callout_info)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct key *key;
71262306a36Sopenharmony_ci	size_t callout_len = 0;
71362306a36Sopenharmony_ci	int ret;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (callout_info)
71662306a36Sopenharmony_ci		callout_len = strlen(callout_info);
71762306a36Sopenharmony_ci	key = request_key_and_link(type, description, domain_tag,
71862306a36Sopenharmony_ci				   callout_info, callout_len,
71962306a36Sopenharmony_ci				   NULL, NULL, KEY_ALLOC_IN_QUOTA);
72062306a36Sopenharmony_ci	if (!IS_ERR(key)) {
72162306a36Sopenharmony_ci		ret = wait_for_key_construction(key, false);
72262306a36Sopenharmony_ci		if (ret < 0) {
72362306a36Sopenharmony_ci			key_put(key);
72462306a36Sopenharmony_ci			return ERR_PTR(ret);
72562306a36Sopenharmony_ci		}
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci	return key;
72862306a36Sopenharmony_ci}
72962306a36Sopenharmony_ciEXPORT_SYMBOL(request_key_tag);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci/**
73262306a36Sopenharmony_ci * request_key_with_auxdata - Request a key with auxiliary data for the upcaller
73362306a36Sopenharmony_ci * @type: The type of key we want.
73462306a36Sopenharmony_ci * @description: The searchable description of the key.
73562306a36Sopenharmony_ci * @domain_tag: The domain in which the key operates.
73662306a36Sopenharmony_ci * @callout_info: The data to pass to the instantiation upcall (or NULL).
73762306a36Sopenharmony_ci * @callout_len: The length of callout_info.
73862306a36Sopenharmony_ci * @aux: Auxiliary data for the upcall.
73962306a36Sopenharmony_ci *
74062306a36Sopenharmony_ci * As for request_key_and_link() except that it does not add the returned key
74162306a36Sopenharmony_ci * to a keyring if found and new keys are always allocated in the user's quota.
74262306a36Sopenharmony_ci *
74362306a36Sopenharmony_ci * Furthermore, it then works as wait_for_key_construction() to wait for the
74462306a36Sopenharmony_ci * completion of keys undergoing construction with a non-interruptible wait.
74562306a36Sopenharmony_ci */
74662306a36Sopenharmony_cistruct key *request_key_with_auxdata(struct key_type *type,
74762306a36Sopenharmony_ci				     const char *description,
74862306a36Sopenharmony_ci				     struct key_tag *domain_tag,
74962306a36Sopenharmony_ci				     const void *callout_info,
75062306a36Sopenharmony_ci				     size_t callout_len,
75162306a36Sopenharmony_ci				     void *aux)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct key *key;
75462306a36Sopenharmony_ci	int ret;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	key = request_key_and_link(type, description, domain_tag,
75762306a36Sopenharmony_ci				   callout_info, callout_len,
75862306a36Sopenharmony_ci				   aux, NULL, KEY_ALLOC_IN_QUOTA);
75962306a36Sopenharmony_ci	if (!IS_ERR(key)) {
76062306a36Sopenharmony_ci		ret = wait_for_key_construction(key, false);
76162306a36Sopenharmony_ci		if (ret < 0) {
76262306a36Sopenharmony_ci			key_put(key);
76362306a36Sopenharmony_ci			return ERR_PTR(ret);
76462306a36Sopenharmony_ci		}
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci	return key;
76762306a36Sopenharmony_ci}
76862306a36Sopenharmony_ciEXPORT_SYMBOL(request_key_with_auxdata);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci/**
77162306a36Sopenharmony_ci * request_key_rcu - Request key from RCU-read-locked context
77262306a36Sopenharmony_ci * @type: The type of key we want.
77362306a36Sopenharmony_ci * @description: The name of the key we want.
77462306a36Sopenharmony_ci * @domain_tag: The domain in which the key operates.
77562306a36Sopenharmony_ci *
77662306a36Sopenharmony_ci * Request a key from a context that we may not sleep in (such as RCU-mode
77762306a36Sopenharmony_ci * pathwalk).  Keys under construction are ignored.
77862306a36Sopenharmony_ci *
77962306a36Sopenharmony_ci * Return a pointer to the found key if successful, -ENOKEY if we couldn't find
78062306a36Sopenharmony_ci * a key or some other error if the key found was unsuitable or inaccessible.
78162306a36Sopenharmony_ci */
78262306a36Sopenharmony_cistruct key *request_key_rcu(struct key_type *type,
78362306a36Sopenharmony_ci			    const char *description,
78462306a36Sopenharmony_ci			    struct key_tag *domain_tag)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct keyring_search_context ctx = {
78762306a36Sopenharmony_ci		.index_key.type		= type,
78862306a36Sopenharmony_ci		.index_key.domain_tag	= domain_tag,
78962306a36Sopenharmony_ci		.index_key.description	= description,
79062306a36Sopenharmony_ci		.index_key.desc_len	= strlen(description),
79162306a36Sopenharmony_ci		.cred			= current_cred(),
79262306a36Sopenharmony_ci		.match_data.cmp		= key_default_cmp,
79362306a36Sopenharmony_ci		.match_data.raw_data	= description,
79462306a36Sopenharmony_ci		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
79562306a36Sopenharmony_ci		.flags			= (KEYRING_SEARCH_DO_STATE_CHECK |
79662306a36Sopenharmony_ci					   KEYRING_SEARCH_SKIP_EXPIRED),
79762306a36Sopenharmony_ci	};
79862306a36Sopenharmony_ci	struct key *key;
79962306a36Sopenharmony_ci	key_ref_t key_ref;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	kenter("%s,%s", type->name, description);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	key = check_cached_key(&ctx);
80462306a36Sopenharmony_ci	if (key)
80562306a36Sopenharmony_ci		return key;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	/* search all the process keyrings for a key */
80862306a36Sopenharmony_ci	key_ref = search_process_keyrings_rcu(&ctx);
80962306a36Sopenharmony_ci	if (IS_ERR(key_ref)) {
81062306a36Sopenharmony_ci		key = ERR_CAST(key_ref);
81162306a36Sopenharmony_ci		if (PTR_ERR(key_ref) == -EAGAIN)
81262306a36Sopenharmony_ci			key = ERR_PTR(-ENOKEY);
81362306a36Sopenharmony_ci	} else {
81462306a36Sopenharmony_ci		key = key_ref_to_ptr(key_ref);
81562306a36Sopenharmony_ci		cache_requested_key(key);
81662306a36Sopenharmony_ci	}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci	kleave(" = %p", key);
81962306a36Sopenharmony_ci	return key;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ciEXPORT_SYMBOL(request_key_rcu);
822