xref: /openbmc/linux/security/keys/request_key.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
276181c13SDavid Howells /* Request a key from userspace
31da177e4SLinus Torvalds  *
476181c13SDavid Howells  * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
51da177e4SLinus Torvalds  * Written by David Howells (dhowells@redhat.com)
61da177e4SLinus Torvalds  *
73db38ed7SKees Cook  * See Documentation/security/keys/request-key.rst
81da177e4SLinus Torvalds  */
91da177e4SLinus Torvalds 
10876979c9SPaul Gortmaker #include <linux/export.h>
111da177e4SLinus Torvalds #include <linux/sched.h>
121da177e4SLinus Torvalds #include <linux/kmod.h>
131da177e4SLinus Torvalds #include <linux/err.h>
143e30148cSDavid Howells #include <linux/keyctl.h>
15fdb89bceSRobert P. J. Day #include <linux/slab.h>
16a58946c1SDavid Howells #include <net/net_namespace.h>
171da177e4SLinus Torvalds #include "internal.h"
18822ad64dSDavid Howells #include <keys/request_key_auth-type.h>
191da177e4SLinus Torvalds 
20e9e349b0SDavid Howells #define key_negative_timeout	60	/* default timeout on a negative key's existence */
21e9e349b0SDavid Howells 
check_cached_key(struct keyring_search_context * ctx)227743c48eSDavid Howells static struct key *check_cached_key(struct keyring_search_context *ctx)
237743c48eSDavid Howells {
247743c48eSDavid Howells #ifdef CONFIG_KEYS_REQUEST_CACHE
257743c48eSDavid Howells 	struct key *key = current->cached_requested_key;
267743c48eSDavid Howells 
277743c48eSDavid Howells 	if (key &&
287743c48eSDavid Howells 	    ctx->match_data.cmp(key, &ctx->match_data) &&
297743c48eSDavid Howells 	    !(key->flags & ((1 << KEY_FLAG_INVALIDATED) |
307743c48eSDavid Howells 			    (1 << KEY_FLAG_REVOKED))))
317743c48eSDavid Howells 		return key_get(key);
327743c48eSDavid Howells #endif
337743c48eSDavid Howells 	return NULL;
347743c48eSDavid Howells }
357743c48eSDavid Howells 
cache_requested_key(struct key * key)367743c48eSDavid Howells static void cache_requested_key(struct key *key)
377743c48eSDavid Howells {
387743c48eSDavid Howells #ifdef CONFIG_KEYS_REQUEST_CACHE
397743c48eSDavid Howells 	struct task_struct *t = current;
407743c48eSDavid Howells 
4147f9e4c9SDavid Howells 	/* Do not cache key if it is a kernel thread */
4247f9e4c9SDavid Howells 	if (!(t->flags & PF_KTHREAD)) {
437743c48eSDavid Howells 		key_put(t->cached_requested_key);
447743c48eSDavid Howells 		t->cached_requested_key = key_get(key);
457743c48eSDavid Howells 		set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
4647f9e4c9SDavid Howells 	}
477743c48eSDavid Howells #endif
487743c48eSDavid Howells }
497743c48eSDavid Howells 
50973c9f4fSDavid Howells /**
51973c9f4fSDavid Howells  * complete_request_key - Complete the construction of a key.
529fd16537SDavid Howells  * @authkey: The authorisation key.
53973c9f4fSDavid Howells  * @error: The success or failute of the construction.
54973c9f4fSDavid Howells  *
55973c9f4fSDavid Howells  * Complete the attempt to construct a key.  The key will be negated
56973c9f4fSDavid Howells  * if an error is indicated.  The authorisation key will be revoked
57973c9f4fSDavid Howells  * unconditionally.
5876181c13SDavid Howells  */
complete_request_key(struct key * authkey,int error)59822ad64dSDavid Howells void complete_request_key(struct key *authkey, int error)
6076181c13SDavid Howells {
61822ad64dSDavid Howells 	struct request_key_auth *rka = get_request_key_auth(authkey);
62822ad64dSDavid Howells 	struct key *key = rka->target_key;
63822ad64dSDavid Howells 
64822ad64dSDavid Howells 	kenter("%d{%d},%d", authkey->serial, key->serial, error);
6576181c13SDavid Howells 
6676181c13SDavid Howells 	if (error < 0)
67822ad64dSDavid Howells 		key_negate_and_link(key, key_negative_timeout, NULL, authkey);
6876181c13SDavid Howells 	else
69822ad64dSDavid Howells 		key_revoke(authkey);
7076181c13SDavid Howells }
7176181c13SDavid Howells EXPORT_SYMBOL(complete_request_key);
7276181c13SDavid Howells 
73973c9f4fSDavid Howells /*
74973c9f4fSDavid Howells  * Initialise a usermode helper that is going to have a specific session
75973c9f4fSDavid Howells  * keyring.
76973c9f4fSDavid Howells  *
77973c9f4fSDavid Howells  * This is called in context of freshly forked kthread before kernel_execve(),
78973c9f4fSDavid Howells  * so we can simply install the desired session_keyring at this point.
79973c9f4fSDavid Howells  */
umh_keys_init(struct subprocess_info * info,struct cred * cred)8087966996SDavid Howells static int umh_keys_init(struct subprocess_info *info, struct cred *cred)
81685bfd2cSOleg Nesterov {
82685bfd2cSOleg Nesterov 	struct key *keyring = info->data;
83973c9f4fSDavid Howells 
84685bfd2cSOleg Nesterov 	return install_session_keyring_to_cred(cred, keyring);
85685bfd2cSOleg Nesterov }
86685bfd2cSOleg Nesterov 
87973c9f4fSDavid Howells /*
88973c9f4fSDavid Howells  * Clean up a usermode helper with session keyring.
89973c9f4fSDavid Howells  */
umh_keys_cleanup(struct subprocess_info * info)90685bfd2cSOleg Nesterov static void umh_keys_cleanup(struct subprocess_info *info)
91685bfd2cSOleg Nesterov {
92685bfd2cSOleg Nesterov 	struct key *keyring = info->data;
93685bfd2cSOleg Nesterov 	key_put(keyring);
94685bfd2cSOleg Nesterov }
95685bfd2cSOleg Nesterov 
96973c9f4fSDavid Howells /*
97973c9f4fSDavid Howells  * Call a usermode helper with a specific session keyring.
98973c9f4fSDavid Howells  */
call_usermodehelper_keys(const char * path,char ** argv,char ** envp,struct key * session_keyring,int wait)99377e7a27SGreg Kroah-Hartman static int call_usermodehelper_keys(const char *path, char **argv, char **envp,
1009d944ef3SOleg Nesterov 					struct key *session_keyring, int wait)
101685bfd2cSOleg Nesterov {
10293997f6dSLucas De Marchi 	struct subprocess_info *info;
10393997f6dSLucas De Marchi 
10493997f6dSLucas De Marchi 	info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL,
10581ab6e7bSBoaz Harrosh 					  umh_keys_init, umh_keys_cleanup,
10693997f6dSLucas De Marchi 					  session_keyring);
10793997f6dSLucas De Marchi 	if (!info)
10893997f6dSLucas De Marchi 		return -ENOMEM;
10993997f6dSLucas De Marchi 
11093997f6dSLucas De Marchi 	key_get(session_keyring);
11193997f6dSLucas De Marchi 	return call_usermodehelper_exec(info, wait);
112685bfd2cSOleg Nesterov }
113685bfd2cSOleg Nesterov 
1141da177e4SLinus Torvalds /*
115973c9f4fSDavid Howells  * Request userspace finish the construction of a key
116b5f545c8SDavid Howells  * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
1171da177e4SLinus Torvalds  */
call_sbin_request_key(struct key * authkey,void * aux)118822ad64dSDavid Howells static int call_sbin_request_key(struct key *authkey, void *aux)
1191da177e4SLinus Torvalds {
120377e7a27SGreg Kroah-Hartman 	static char const request_key[] = "/sbin/request-key";
121822ad64dSDavid Howells 	struct request_key_auth *rka = get_request_key_auth(authkey);
12286a264abSDavid Howells 	const struct cred *cred = current_cred();
1231da177e4SLinus Torvalds 	key_serial_t prkey, sskey;
1240f44e4d9SDavid Howells 	struct key *key = rka->target_key, *keyring, *session, *user_session;
125b5f545c8SDavid Howells 	char *argv[9], *envp[3], uid_str[12], gid_str[12];
1261da177e4SLinus Torvalds 	char key_str[12], keyring_str[3][12];
127b5f545c8SDavid Howells 	char desc[20];
1283e30148cSDavid Howells 	int ret, i;
1293e30148cSDavid Howells 
130822ad64dSDavid Howells 	kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op);
1313e30148cSDavid Howells 
1320f44e4d9SDavid Howells 	ret = look_up_user_keyrings(NULL, &user_session);
1338bbf4976SDavid Howells 	if (ret < 0)
1340f44e4d9SDavid Howells 		goto error_us;
1358bbf4976SDavid Howells 
136b5f545c8SDavid Howells 	/* allocate a new session keyring */
137b5f545c8SDavid Howells 	sprintf(desc, "_req.%u", key->serial);
138b5f545c8SDavid Howells 
139d84f4f99SDavid Howells 	cred = get_current_cred();
140d84f4f99SDavid Howells 	keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
141028db3e2SLinus Torvalds 				KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
142028db3e2SLinus Torvalds 				KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
143d84f4f99SDavid Howells 	put_cred(cred);
144b5f545c8SDavid Howells 	if (IS_ERR(keyring)) {
145b5f545c8SDavid Howells 		ret = PTR_ERR(keyring);
146b5f545c8SDavid Howells 		goto error_alloc;
1473e30148cSDavid Howells 	}
1481da177e4SLinus Torvalds 
149b5f545c8SDavid Howells 	/* attach the auth key to the session keyring */
150896903c2SDavid Howells 	ret = key_link(keyring, authkey);
151b5f545c8SDavid Howells 	if (ret < 0)
152b5f545c8SDavid Howells 		goto error_link;
153b5f545c8SDavid Howells 
1541da177e4SLinus Torvalds 	/* record the UID and GID */
1559a56c2dbSEric W. Biederman 	sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid));
1569a56c2dbSEric W. Biederman 	sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid));
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds 	/* we say which key is under construction */
1591da177e4SLinus Torvalds 	sprintf(key_str, "%d", key->serial);
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	/* we specify the process's default keyrings */
1621da177e4SLinus Torvalds 	sprintf(keyring_str[0], "%d",
163d84f4f99SDavid Howells 		cred->thread_keyring ? cred->thread_keyring->serial : 0);
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	prkey = 0;
1663a50597dSDavid Howells 	if (cred->process_keyring)
1673a50597dSDavid Howells 		prkey = cred->process_keyring->serial;
1685ad18a0dSJustin P. Mattock 	sprintf(keyring_str[1], "%d", prkey);
1691da177e4SLinus Torvalds 
1705c7e372cSJann Horn 	session = cred->session_keyring;
17193b4a44fSDavid Howells 	if (!session)
1720f44e4d9SDavid Howells 		session = user_session;
17393b4a44fSDavid Howells 	sskey = session->serial;
1743e30148cSDavid Howells 
1751da177e4SLinus Torvalds 	sprintf(keyring_str[2], "%d", sskey);
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	/* set up a minimal environment */
1781da177e4SLinus Torvalds 	i = 0;
1791da177e4SLinus Torvalds 	envp[i++] = "HOME=/";
1801da177e4SLinus Torvalds 	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
1811da177e4SLinus Torvalds 	envp[i] = NULL;
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	/* set up the argument list */
1841da177e4SLinus Torvalds 	i = 0;
185377e7a27SGreg Kroah-Hartman 	argv[i++] = (char *)request_key;
186822ad64dSDavid Howells 	argv[i++] = (char *)rka->op;
1871da177e4SLinus Torvalds 	argv[i++] = key_str;
1881da177e4SLinus Torvalds 	argv[i++] = uid_str;
1891da177e4SLinus Torvalds 	argv[i++] = gid_str;
1901da177e4SLinus Torvalds 	argv[i++] = keyring_str[0];
1911da177e4SLinus Torvalds 	argv[i++] = keyring_str[1];
1921da177e4SLinus Torvalds 	argv[i++] = keyring_str[2];
1931da177e4SLinus Torvalds 	argv[i] = NULL;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	/* do it */
196377e7a27SGreg Kroah-Hartman 	ret = call_usermodehelper_keys(request_key, argv, envp, keyring,
19786313c48SJeremy Fitzhardinge 				       UMH_WAIT_PROC);
19876181c13SDavid Howells 	kdebug("usermode -> 0x%x", ret);
19976181c13SDavid Howells 	if (ret >= 0) {
20076181c13SDavid Howells 		/* ret is the exit/wait code */
20176181c13SDavid Howells 		if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) ||
20276181c13SDavid Howells 		    key_validate(key) < 0)
20376181c13SDavid Howells 			ret = -ENOKEY;
20476181c13SDavid Howells 		else
20576181c13SDavid Howells 			/* ignore any errors from userspace if the key was
20676181c13SDavid Howells 			 * instantiated */
20776181c13SDavid Howells 			ret = 0;
20876181c13SDavid Howells 	}
2093e30148cSDavid Howells 
210b5f545c8SDavid Howells error_link:
211b5f545c8SDavid Howells 	key_put(keyring);
2123e30148cSDavid Howells 
213b5f545c8SDavid Howells error_alloc:
2140f44e4d9SDavid Howells 	key_put(user_session);
2150f44e4d9SDavid Howells error_us:
216822ad64dSDavid Howells 	complete_request_key(authkey, ret);
217d84f4f99SDavid Howells 	kleave(" = %d", ret);
2183e30148cSDavid Howells 	return ret;
21976181c13SDavid Howells }
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds /*
222973c9f4fSDavid Howells  * Call out to userspace for key construction.
223973c9f4fSDavid Howells  *
224973c9f4fSDavid Howells  * Program failure is ignored in favour of key status.
2251da177e4SLinus Torvalds  */
construct_key(struct key * key,const void * callout_info,size_t callout_len,void * aux,struct key * dest_keyring)2264a38e122SDavid Howells static int construct_key(struct key *key, const void *callout_info,
2278bbf4976SDavid Howells 			 size_t callout_len, void *aux,
2288bbf4976SDavid Howells 			 struct key *dest_keyring)
2291da177e4SLinus Torvalds {
230b5f545c8SDavid Howells 	request_key_actor_t actor;
23176181c13SDavid Howells 	struct key *authkey;
23276181c13SDavid Howells 	int ret;
2331da177e4SLinus Torvalds 
2344a38e122SDavid Howells 	kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux);
2353e30148cSDavid Howells 
236b5f545c8SDavid Howells 	/* allocate an authorisation key */
237822ad64dSDavid Howells 	authkey = request_key_auth_new(key, "create", callout_info, callout_len,
2388bbf4976SDavid Howells 				       dest_keyring);
239822ad64dSDavid Howells 	if (IS_ERR(authkey))
240822ad64dSDavid Howells 		return PTR_ERR(authkey);
241b5f545c8SDavid Howells 
242822ad64dSDavid Howells 	/* Make the call */
243b5f545c8SDavid Howells 	actor = call_sbin_request_key;
24476181c13SDavid Howells 	if (key->type->request_key)
24576181c13SDavid Howells 		actor = key->type->request_key;
2461da177e4SLinus Torvalds 
247822ad64dSDavid Howells 	ret = actor(authkey, aux);
2481da177e4SLinus Torvalds 
24976181c13SDavid Howells 	/* check that the actor called complete_request_key() prior to
25076181c13SDavid Howells 	 * returning an error */
25176181c13SDavid Howells 	WARN_ON(ret < 0 &&
252a09003b5SDavid Howells 		!test_bit(KEY_FLAG_INVALIDATED, &authkey->flags));
2531da177e4SLinus Torvalds 
254822ad64dSDavid Howells 	key_put(authkey);
25576181c13SDavid Howells 	kleave(" = %d", ret);
25676181c13SDavid Howells 	return ret;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds /*
260973c9f4fSDavid Howells  * Get the appropriate destination keyring for the request.
261973c9f4fSDavid Howells  *
262973c9f4fSDavid Howells  * The keyring selected is returned with an extra reference upon it which the
263973c9f4fSDavid Howells  * caller must release.
2641da177e4SLinus Torvalds  */
construct_get_dest_keyring(struct key ** _dest_keyring)2654dca6ea1SEric Biggers static int construct_get_dest_keyring(struct key **_dest_keyring)
2663e30148cSDavid Howells {
2678bbf4976SDavid Howells 	struct request_key_auth *rka;
268bb952bb9SDavid Howells 	const struct cred *cred = current_cred();
2698bbf4976SDavid Howells 	struct key *dest_keyring = *_dest_keyring, *authkey;
2704dca6ea1SEric Biggers 	int ret;
2713e30148cSDavid Howells 
2728bbf4976SDavid Howells 	kenter("%p", dest_keyring);
2733e30148cSDavid Howells 
2743e30148cSDavid Howells 	/* find the appropriate keyring */
2758bbf4976SDavid Howells 	if (dest_keyring) {
2768bbf4976SDavid Howells 		/* the caller supplied one */
2778bbf4976SDavid Howells 		key_get(dest_keyring);
2788bbf4976SDavid Howells 	} else {
2794dca6ea1SEric Biggers 		bool do_perm_check = true;
2804dca6ea1SEric Biggers 
2818bbf4976SDavid Howells 		/* use a default keyring; falling through the cases until we
2828bbf4976SDavid Howells 		 * find one that we actually have */
283bb952bb9SDavid Howells 		switch (cred->jit_keyring) {
2843e30148cSDavid Howells 		case KEY_REQKEY_DEFL_DEFAULT:
2858bbf4976SDavid Howells 		case KEY_REQKEY_DEFL_REQUESTOR_KEYRING:
286bb952bb9SDavid Howells 			if (cred->request_key_auth) {
287bb952bb9SDavid Howells 				authkey = cred->request_key_auth;
2888bbf4976SDavid Howells 				down_read(&authkey->sem);
289822ad64dSDavid Howells 				rka = get_request_key_auth(authkey);
2908bbf4976SDavid Howells 				if (!test_bit(KEY_FLAG_REVOKED,
2918bbf4976SDavid Howells 					      &authkey->flags))
2928bbf4976SDavid Howells 					dest_keyring =
2938bbf4976SDavid Howells 						key_get(rka->dest_keyring);
2948bbf4976SDavid Howells 				up_read(&authkey->sem);
2954dca6ea1SEric Biggers 				if (dest_keyring) {
2964dca6ea1SEric Biggers 					do_perm_check = false;
2978bbf4976SDavid Howells 					break;
2988bbf4976SDavid Howells 				}
2994dca6ea1SEric Biggers 			}
3008bbf4976SDavid Howells 
301df561f66SGustavo A. R. Silva 			fallthrough;
3023e30148cSDavid Howells 		case KEY_REQKEY_DEFL_THREAD_KEYRING:
303bb952bb9SDavid Howells 			dest_keyring = key_get(cred->thread_keyring);
3043e30148cSDavid Howells 			if (dest_keyring)
3053e30148cSDavid Howells 				break;
3063e30148cSDavid Howells 
307df561f66SGustavo A. R. Silva 			fallthrough;
3083e30148cSDavid Howells 		case KEY_REQKEY_DEFL_PROCESS_KEYRING:
3093a50597dSDavid Howells 			dest_keyring = key_get(cred->process_keyring);
3103e30148cSDavid Howells 			if (dest_keyring)
3113e30148cSDavid Howells 				break;
3123e30148cSDavid Howells 
313df561f66SGustavo A. R. Silva 			fallthrough;
3143e30148cSDavid Howells 		case KEY_REQKEY_DEFL_SESSION_KEYRING:
3155c7e372cSJann Horn 			dest_keyring = key_get(cred->session_keyring);
3163e30148cSDavid Howells 
3173e30148cSDavid Howells 			if (dest_keyring)
3183e30148cSDavid Howells 				break;
3193e30148cSDavid Howells 
320df561f66SGustavo A. R. Silva 			fallthrough;
3213e30148cSDavid Howells 		case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
3220f44e4d9SDavid Howells 			ret = look_up_user_keyrings(NULL, &dest_keyring);
3230f44e4d9SDavid Howells 			if (ret < 0)
3240f44e4d9SDavid Howells 				return ret;
3253e30148cSDavid Howells 			break;
3263e30148cSDavid Howells 
3273e30148cSDavid Howells 		case KEY_REQKEY_DEFL_USER_KEYRING:
3280f44e4d9SDavid Howells 			ret = look_up_user_keyrings(&dest_keyring, NULL);
3290f44e4d9SDavid Howells 			if (ret < 0)
3300f44e4d9SDavid Howells 				return ret;
3313e30148cSDavid Howells 			break;
3323e30148cSDavid Howells 
3333e30148cSDavid Howells 		case KEY_REQKEY_DEFL_GROUP_KEYRING:
3343e30148cSDavid Howells 		default:
3353e30148cSDavid Howells 			BUG();
3363e30148cSDavid Howells 		}
3374dca6ea1SEric Biggers 
3384dca6ea1SEric Biggers 		/*
3394dca6ea1SEric Biggers 		 * Require Write permission on the keyring.  This is essential
3404dca6ea1SEric Biggers 		 * because the default keyring may be the session keyring, and
3414dca6ea1SEric Biggers 		 * joining a keyring only requires Search permission.
3424dca6ea1SEric Biggers 		 *
3434dca6ea1SEric Biggers 		 * However, this check is skipped for the "requestor keyring" so
3444dca6ea1SEric Biggers 		 * that /sbin/request-key can itself use request_key() to add
3454dca6ea1SEric Biggers 		 * keys to the original requestor's destination keyring.
3464dca6ea1SEric Biggers 		 */
3474dca6ea1SEric Biggers 		if (dest_keyring && do_perm_check) {
3484dca6ea1SEric Biggers 			ret = key_permission(make_key_ref(dest_keyring, 1),
3494dca6ea1SEric Biggers 					     KEY_NEED_WRITE);
3504dca6ea1SEric Biggers 			if (ret) {
3514dca6ea1SEric Biggers 				key_put(dest_keyring);
3524dca6ea1SEric Biggers 				return ret;
3534dca6ea1SEric Biggers 			}
3544dca6ea1SEric Biggers 		}
3553e30148cSDavid Howells 	}
3563e30148cSDavid Howells 
3578bbf4976SDavid Howells 	*_dest_keyring = dest_keyring;
3588bbf4976SDavid Howells 	kleave(" [dk %d]", key_serial(dest_keyring));
3594dca6ea1SEric Biggers 	return 0;
36076181c13SDavid Howells }
3613e30148cSDavid Howells 
36276181c13SDavid Howells /*
363973c9f4fSDavid Howells  * Allocate a new key in under-construction state and attempt to link it in to
364973c9f4fSDavid Howells  * the requested keyring.
365973c9f4fSDavid Howells  *
366973c9f4fSDavid Howells  * May return a key that's already under construction instead if there was a
367973c9f4fSDavid Howells  * race between two thread calling request_key().
36876181c13SDavid Howells  */
construct_alloc_key(struct keyring_search_context * ctx,struct key * dest_keyring,unsigned long flags,struct key_user * user,struct key ** _key)3694bdf0bc3SDavid Howells static int construct_alloc_key(struct keyring_search_context *ctx,
37076181c13SDavid Howells 			       struct key *dest_keyring,
37176181c13SDavid Howells 			       unsigned long flags,
37276181c13SDavid Howells 			       struct key_user *user,
37376181c13SDavid Howells 			       struct key **_key)
37476181c13SDavid Howells {
375df593ee2SDavid Howells 	struct assoc_array_edit *edit = NULL;
37676181c13SDavid Howells 	struct key *key;
377028db3e2SLinus Torvalds 	key_perm_t perm;
37876181c13SDavid Howells 	key_ref_t key_ref;
3792b9e4688SDavid Howells 	int ret;
3803e30148cSDavid Howells 
3814bdf0bc3SDavid Howells 	kenter("%s,%s,,,",
3824bdf0bc3SDavid Howells 	       ctx->index_key.type->name, ctx->index_key.description);
38376181c13SDavid Howells 
384f70e2e06SDavid Howells 	*_key = NULL;
38576181c13SDavid Howells 	mutex_lock(&user->cons_lock);
38676181c13SDavid Howells 
387028db3e2SLinus Torvalds 	perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
388028db3e2SLinus Torvalds 	perm |= KEY_USR_VIEW;
389028db3e2SLinus Torvalds 	if (ctx->index_key.type->read)
390028db3e2SLinus Torvalds 		perm |= KEY_POS_READ;
391028db3e2SLinus Torvalds 	if (ctx->index_key.type == &key_type_keyring ||
392028db3e2SLinus Torvalds 	    ctx->index_key.type->update)
393028db3e2SLinus Torvalds 		perm |= KEY_POS_WRITE;
394028db3e2SLinus Torvalds 
3954bdf0bc3SDavid Howells 	key = key_alloc(ctx->index_key.type, ctx->index_key.description,
3964bdf0bc3SDavid Howells 			ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
397028db3e2SLinus Torvalds 			perm, flags, NULL);
39876181c13SDavid Howells 	if (IS_ERR(key))
39976181c13SDavid Howells 		goto alloc_failed;
40076181c13SDavid Howells 
40176181c13SDavid Howells 	set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
40276181c13SDavid Howells 
403f70e2e06SDavid Howells 	if (dest_keyring) {
404*d5590152SPetr Pavlu 		ret = __key_link_lock(dest_keyring, &key->index_key);
405df593ee2SDavid Howells 		if (ret < 0)
406df593ee2SDavid Howells 			goto link_lock_failed;
407f70e2e06SDavid Howells 	}
40876181c13SDavid Howells 
409*d5590152SPetr Pavlu 	/*
410*d5590152SPetr Pavlu 	 * Attach the key to the destination keyring under lock, but we do need
41176181c13SDavid Howells 	 * to do another check just in case someone beat us to it whilst we
412*d5590152SPetr Pavlu 	 * waited for locks.
413*d5590152SPetr Pavlu 	 *
414*d5590152SPetr Pavlu 	 * The caller might specify a comparison function which looks for keys
415*d5590152SPetr Pavlu 	 * that do not exactly match but are still equivalent from the caller's
416*d5590152SPetr Pavlu 	 * perspective. The __key_link_begin() operation must be done only after
417*d5590152SPetr Pavlu 	 * an actual key is determined.
418*d5590152SPetr Pavlu 	 */
41976181c13SDavid Howells 	mutex_lock(&key_construction_mutex);
42076181c13SDavid Howells 
421e59428f7SDavid Howells 	rcu_read_lock();
422e59428f7SDavid Howells 	key_ref = search_process_keyrings_rcu(ctx);
423e59428f7SDavid Howells 	rcu_read_unlock();
42476181c13SDavid Howells 	if (!IS_ERR(key_ref))
42576181c13SDavid Howells 		goto key_already_present;
42676181c13SDavid Howells 
427*d5590152SPetr Pavlu 	if (dest_keyring) {
428*d5590152SPetr Pavlu 		ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
429*d5590152SPetr Pavlu 		if (ret < 0)
430*d5590152SPetr Pavlu 			goto link_alloc_failed;
431f7e47677SDavid Howells 		__key_link(dest_keyring, key, &edit);
432*d5590152SPetr Pavlu 	}
43376181c13SDavid Howells 
43476181c13SDavid Howells 	mutex_unlock(&key_construction_mutex);
43534574dd1SDavid Howells 	if (dest_keyring)
436*d5590152SPetr Pavlu 		__key_link_end(dest_keyring, &key->index_key, edit);
43776181c13SDavid Howells 	mutex_unlock(&user->cons_lock);
43876181c13SDavid Howells 	*_key = key;
43976181c13SDavid Howells 	kleave(" = 0 [%d]", key_serial(key));
44076181c13SDavid Howells 	return 0;
44176181c13SDavid Howells 
4422b9e4688SDavid Howells 	/* the key is now present - we tell the caller that we found it by
4432b9e4688SDavid Howells 	 * returning -EINPROGRESS  */
44476181c13SDavid Howells key_already_present:
445f70e2e06SDavid Howells 	key_put(key);
44676181c13SDavid Howells 	mutex_unlock(&key_construction_mutex);
447f70e2e06SDavid Howells 	key = key_ref_to_ptr(key_ref);
44803449cd9SDavid Howells 	if (dest_keyring) {
449*d5590152SPetr Pavlu 		ret = __key_link_begin(dest_keyring, &key->index_key, &edit);
450*d5590152SPetr Pavlu 		if (ret < 0)
451*d5590152SPetr Pavlu 			goto link_alloc_failed_unlocked;
452f70e2e06SDavid Howells 		ret = __key_link_check_live_key(dest_keyring, key);
453f70e2e06SDavid Howells 		if (ret == 0)
454f7e47677SDavid Howells 			__key_link(dest_keyring, key, &edit);
455*d5590152SPetr Pavlu 		__key_link_end(dest_keyring, &key->index_key, edit);
456f70e2e06SDavid Howells 		if (ret < 0)
457f70e2e06SDavid Howells 			goto link_check_failed;
45803449cd9SDavid Howells 	}
45976181c13SDavid Howells 	mutex_unlock(&user->cons_lock);
460f70e2e06SDavid Howells 	*_key = key;
46176181c13SDavid Howells 	kleave(" = -EINPROGRESS [%d]", key_serial(key));
46276181c13SDavid Howells 	return -EINPROGRESS;
46376181c13SDavid Howells 
464f70e2e06SDavid Howells link_check_failed:
465f70e2e06SDavid Howells 	mutex_unlock(&user->cons_lock);
466f70e2e06SDavid Howells 	key_put(key);
467f70e2e06SDavid Howells 	kleave(" = %d [linkcheck]", ret);
468f70e2e06SDavid Howells 	return ret;
469f70e2e06SDavid Howells 
470*d5590152SPetr Pavlu link_alloc_failed:
471*d5590152SPetr Pavlu 	mutex_unlock(&key_construction_mutex);
472*d5590152SPetr Pavlu link_alloc_failed_unlocked:
473*d5590152SPetr Pavlu 	__key_link_end(dest_keyring, &key->index_key, edit);
474df593ee2SDavid Howells link_lock_failed:
475f70e2e06SDavid Howells 	mutex_unlock(&user->cons_lock);
476d0709f1eSDavid Jeffery 	key_put(key);
477f70e2e06SDavid Howells 	kleave(" = %d [prelink]", ret);
478f70e2e06SDavid Howells 	return ret;
479f70e2e06SDavid Howells 
48076181c13SDavid Howells alloc_failed:
48176181c13SDavid Howells 	mutex_unlock(&user->cons_lock);
48276181c13SDavid Howells 	kleave(" = %ld", PTR_ERR(key));
48376181c13SDavid Howells 	return PTR_ERR(key);
48476181c13SDavid Howells }
48576181c13SDavid Howells 
48676181c13SDavid Howells /*
487973c9f4fSDavid Howells  * Commence key construction.
48876181c13SDavid Howells  */
construct_key_and_link(struct keyring_search_context * ctx,const char * callout_info,size_t callout_len,void * aux,struct key * dest_keyring,unsigned long flags)4894bdf0bc3SDavid Howells static struct key *construct_key_and_link(struct keyring_search_context *ctx,
49076181c13SDavid Howells 					  const char *callout_info,
4914a38e122SDavid Howells 					  size_t callout_len,
49276181c13SDavid Howells 					  void *aux,
49376181c13SDavid Howells 					  struct key *dest_keyring,
49476181c13SDavid Howells 					  unsigned long flags)
49576181c13SDavid Howells {
49676181c13SDavid Howells 	struct key_user *user;
49776181c13SDavid Howells 	struct key *key;
49876181c13SDavid Howells 	int ret;
49976181c13SDavid Howells 
500d84f4f99SDavid Howells 	kenter("");
501d84f4f99SDavid Howells 
502911b79cdSDavid Howells 	if (ctx->index_key.type == &key_type_keyring)
503911b79cdSDavid Howells 		return ERR_PTR(-EPERM);
504911b79cdSDavid Howells 
5054dca6ea1SEric Biggers 	ret = construct_get_dest_keyring(&dest_keyring);
5064dca6ea1SEric Biggers 	if (ret)
5074dca6ea1SEric Biggers 		goto error;
50876181c13SDavid Howells 
5094dca6ea1SEric Biggers 	user = key_user_lookup(current_fsuid());
5104dca6ea1SEric Biggers 	if (!user) {
5114dca6ea1SEric Biggers 		ret = -ENOMEM;
5124dca6ea1SEric Biggers 		goto error_put_dest_keyring;
5134dca6ea1SEric Biggers 	}
5148bbf4976SDavid Howells 
515028db3e2SLinus Torvalds 	ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key);
51676181c13SDavid Howells 	key_user_put(user);
51776181c13SDavid Howells 
51876181c13SDavid Howells 	if (ret == 0) {
5198bbf4976SDavid Howells 		ret = construct_key(key, callout_info, callout_len, aux,
5208bbf4976SDavid Howells 				    dest_keyring);
521d84f4f99SDavid Howells 		if (ret < 0) {
522d84f4f99SDavid Howells 			kdebug("cons failed");
52376181c13SDavid Howells 			goto construction_failed;
52476181c13SDavid Howells 		}
5252b9e4688SDavid Howells 	} else if (ret == -EINPROGRESS) {
5262b9e4688SDavid Howells 		ret = 0;
5272b9e4688SDavid Howells 	} else {
5284dca6ea1SEric Biggers 		goto error_put_dest_keyring;
529d84f4f99SDavid Howells 	}
53076181c13SDavid Howells 
5318bbf4976SDavid Howells 	key_put(dest_keyring);
532d84f4f99SDavid Howells 	kleave(" = key %d", key_serial(key));
53376181c13SDavid Howells 	return key;
53476181c13SDavid Howells 
53576181c13SDavid Howells construction_failed:
53676181c13SDavid Howells 	key_negate_and_link(key, key_negative_timeout, NULL, NULL);
53776181c13SDavid Howells 	key_put(key);
5384dca6ea1SEric Biggers error_put_dest_keyring:
5398bbf4976SDavid Howells 	key_put(dest_keyring);
5404dca6ea1SEric Biggers error:
541d84f4f99SDavid Howells 	kleave(" = %d", ret);
54276181c13SDavid Howells 	return ERR_PTR(ret);
54376181c13SDavid Howells }
54476181c13SDavid Howells 
545973c9f4fSDavid Howells /**
546973c9f4fSDavid Howells  * request_key_and_link - Request a key and cache it in a keyring.
547973c9f4fSDavid Howells  * @type: The type of key we want.
548973c9f4fSDavid Howells  * @description: The searchable description of the key.
549a58946c1SDavid Howells  * @domain_tag: The domain in which the key operates.
550973c9f4fSDavid Howells  * @callout_info: The data to pass to the instantiation upcall (or NULL).
551973c9f4fSDavid Howells  * @callout_len: The length of callout_info.
552973c9f4fSDavid Howells  * @aux: Auxiliary data for the upcall.
553973c9f4fSDavid Howells  * @dest_keyring: Where to cache the key.
554973c9f4fSDavid Howells  * @flags: Flags to key_alloc().
555973c9f4fSDavid Howells  *
556a58946c1SDavid Howells  * A key matching the specified criteria (type, description, domain_tag) is
557a58946c1SDavid Howells  * searched for in the process's keyrings and returned with its usage count
558a58946c1SDavid Howells  * incremented if found.  Otherwise, if callout_info is not NULL, a key will be
559a58946c1SDavid Howells  * allocated and some service (probably in userspace) will be asked to
560a58946c1SDavid Howells  * instantiate it.
561973c9f4fSDavid Howells  *
562973c9f4fSDavid Howells  * If successfully found or created, the key will be linked to the destination
563973c9f4fSDavid Howells  * keyring if one is provided.
564973c9f4fSDavid Howells  *
565973c9f4fSDavid Howells  * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED
566973c9f4fSDavid Howells  * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was
567973c9f4fSDavid Howells  * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT
568973c9f4fSDavid Howells  * if insufficient key quota was available to create a new key; or -ENOMEM if
569973c9f4fSDavid Howells  * insufficient memory was available.
570973c9f4fSDavid Howells  *
571973c9f4fSDavid Howells  * If the returned key was created, then it may still be under construction,
572973c9f4fSDavid Howells  * and wait_for_key_construction() should be used to wait for that to complete.
5731da177e4SLinus Torvalds  */
request_key_and_link(struct key_type * type,const char * description,struct key_tag * domain_tag,const void * callout_info,size_t callout_len,void * aux,struct key * dest_keyring,unsigned long flags)5743e30148cSDavid Howells struct key *request_key_and_link(struct key_type *type,
5751da177e4SLinus Torvalds 				 const char *description,
576a58946c1SDavid Howells 				 struct key_tag *domain_tag,
5774a38e122SDavid Howells 				 const void *callout_info,
5784a38e122SDavid Howells 				 size_t callout_len,
5794e54f085SDavid Howells 				 void *aux,
5807e047ef5SDavid Howells 				 struct key *dest_keyring,
5817e047ef5SDavid Howells 				 unsigned long flags)
5821da177e4SLinus Torvalds {
5834bdf0bc3SDavid Howells 	struct keyring_search_context ctx = {
5844bdf0bc3SDavid Howells 		.index_key.type		= type,
585a58946c1SDavid Howells 		.index_key.domain_tag	= domain_tag,
5864bdf0bc3SDavid Howells 		.index_key.description	= description,
587ede0fa98SEric Biggers 		.index_key.desc_len	= strlen(description),
5884bdf0bc3SDavid Howells 		.cred			= current_cred(),
589c06cfb08SDavid Howells 		.match_data.cmp		= key_default_cmp,
59046291959SDavid Howells 		.match_data.raw_data	= description,
59146291959SDavid Howells 		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
5920b0a8415SDavid Howells 		.flags			= (KEYRING_SEARCH_DO_STATE_CHECK |
593dcf49dbcSDavid Howells 					   KEYRING_SEARCH_SKIP_EXPIRED |
594dcf49dbcSDavid Howells 					   KEYRING_SEARCH_RECURSE),
5954bdf0bc3SDavid Howells 	};
5961da177e4SLinus Torvalds 	struct key *key;
597664cceb0SDavid Howells 	key_ref_t key_ref;
5982b9e4688SDavid Howells 	int ret;
5991da177e4SLinus Torvalds 
6004a38e122SDavid Howells 	kenter("%s,%s,%p,%zu,%p,%p,%lx",
6014bdf0bc3SDavid Howells 	       ctx.index_key.type->name, ctx.index_key.description,
6024bdf0bc3SDavid Howells 	       callout_info, callout_len, aux, dest_keyring, flags);
6033e30148cSDavid Howells 
60446291959SDavid Howells 	if (type->match_preparse) {
60546291959SDavid Howells 		ret = type->match_preparse(&ctx.match_data);
60646291959SDavid Howells 		if (ret < 0) {
60746291959SDavid Howells 			key = ERR_PTR(ret);
60846291959SDavid Howells 			goto error;
60946291959SDavid Howells 		}
61046291959SDavid Howells 	}
61146291959SDavid Howells 
6127743c48eSDavid Howells 	key = check_cached_key(&ctx);
6137743c48eSDavid Howells 	if (key)
614846d2db3SEric Biggers 		goto error_free;
6157743c48eSDavid Howells 
6161da177e4SLinus Torvalds 	/* search all the process keyrings for a key */
617e59428f7SDavid Howells 	rcu_read_lock();
618e59428f7SDavid Howells 	key_ref = search_process_keyrings_rcu(&ctx);
619e59428f7SDavid Howells 	rcu_read_unlock();
6201da177e4SLinus Torvalds 
621664cceb0SDavid Howells 	if (!IS_ERR(key_ref)) {
622504b69ebSDavid Howells 		if (dest_keyring) {
623504b69ebSDavid Howells 			ret = key_task_permission(key_ref, current_cred(),
624504b69ebSDavid Howells 						  KEY_NEED_LINK);
625504b69ebSDavid Howells 			if (ret < 0) {
626504b69ebSDavid Howells 				key_ref_put(key_ref);
627504b69ebSDavid Howells 				key = ERR_PTR(ret);
628504b69ebSDavid Howells 				goto error_free;
629504b69ebSDavid Howells 			}
630504b69ebSDavid Howells 		}
631504b69ebSDavid Howells 
632664cceb0SDavid Howells 		key = key_ref_to_ptr(key_ref);
63303449cd9SDavid Howells 		if (dest_keyring) {
6342b9e4688SDavid Howells 			ret = key_link(dest_keyring, key);
6352b9e4688SDavid Howells 			if (ret < 0) {
6362b9e4688SDavid Howells 				key_put(key);
6372b9e4688SDavid Howells 				key = ERR_PTR(ret);
63846291959SDavid Howells 				goto error_free;
6392b9e4688SDavid Howells 			}
64003449cd9SDavid Howells 		}
6417743c48eSDavid Howells 
6427743c48eSDavid Howells 		/* Only cache the key on immediate success */
6437743c48eSDavid Howells 		cache_requested_key(key);
64476181c13SDavid Howells 	} else if (PTR_ERR(key_ref) != -EAGAIN) {
645e231c2eeSDavid Howells 		key = ERR_CAST(key_ref);
64676181c13SDavid Howells 	} else  {
6471da177e4SLinus Torvalds 		/* the search failed, but the keyrings were searchable, so we
6481da177e4SLinus Torvalds 		 * should consult userspace if we can */
6491da177e4SLinus Torvalds 		key = ERR_PTR(-ENOKEY);
6501da177e4SLinus Torvalds 		if (!callout_info)
65146291959SDavid Howells 			goto error_free;
6521da177e4SLinus Torvalds 
6534bdf0bc3SDavid Howells 		key = construct_key_and_link(&ctx, callout_info, callout_len,
654028db3e2SLinus Torvalds 					     aux, dest_keyring, flags);
6551da177e4SLinus Torvalds 	}
6561da177e4SLinus Torvalds 
65746291959SDavid Howells error_free:
65846291959SDavid Howells 	if (type->match_free)
65946291959SDavid Howells 		type->match_free(&ctx.match_data);
6601da177e4SLinus Torvalds error:
6613e30148cSDavid Howells 	kleave(" = %p", key);
6621da177e4SLinus Torvalds 	return key;
66376181c13SDavid Howells }
6641da177e4SLinus Torvalds 
665973c9f4fSDavid Howells /**
666973c9f4fSDavid Howells  * wait_for_key_construction - Wait for construction of a key to complete
667973c9f4fSDavid Howells  * @key: The key being waited for.
668973c9f4fSDavid Howells  * @intr: Whether to wait interruptibly.
669973c9f4fSDavid Howells  *
670973c9f4fSDavid Howells  * Wait for a key to finish being constructed.
671973c9f4fSDavid Howells  *
672973c9f4fSDavid Howells  * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY
673973c9f4fSDavid Howells  * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was
674973c9f4fSDavid Howells  * revoked or expired.
67576181c13SDavid Howells  */
wait_for_key_construction(struct key * key,bool intr)67676181c13SDavid Howells int wait_for_key_construction(struct key *key, bool intr)
67776181c13SDavid Howells {
67876181c13SDavid Howells 	int ret;
6793e30148cSDavid Howells 
68076181c13SDavid Howells 	ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT,
68176181c13SDavid Howells 			  intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
68274316201SNeilBrown 	if (ret)
68374316201SNeilBrown 		return -ERESTARTSYS;
684363b02daSDavid Howells 	ret = key_read_state(key);
685363b02daSDavid Howells 	if (ret < 0)
686363b02daSDavid Howells 		return ret;
68776181c13SDavid Howells 	return key_validate(key);
68876181c13SDavid Howells }
68976181c13SDavid Howells EXPORT_SYMBOL(wait_for_key_construction);
6903e30148cSDavid Howells 
691973c9f4fSDavid Howells /**
692a58946c1SDavid Howells  * request_key_tag - Request a key and wait for construction
693973c9f4fSDavid Howells  * @type: Type of key.
694973c9f4fSDavid Howells  * @description: The searchable description of the key.
695a58946c1SDavid Howells  * @domain_tag: The domain in which the key operates.
696973c9f4fSDavid Howells  * @callout_info: The data to pass to the instantiation upcall (or NULL).
697973c9f4fSDavid Howells  *
698973c9f4fSDavid Howells  * As for request_key_and_link() except that it does not add the returned key
699973c9f4fSDavid Howells  * to a keyring if found, new keys are always allocated in the user's quota,
700973c9f4fSDavid Howells  * the callout_info must be a NUL-terminated string and no auxiliary data can
701973c9f4fSDavid Howells  * be passed.
702973c9f4fSDavid Howells  *
703973c9f4fSDavid Howells  * Furthermore, it then works as wait_for_key_construction() to wait for the
704973c9f4fSDavid Howells  * completion of keys undergoing construction with a non-interruptible wait.
7053e30148cSDavid Howells  */
request_key_tag(struct key_type * type,const char * description,struct key_tag * domain_tag,const char * callout_info)706a58946c1SDavid Howells struct key *request_key_tag(struct key_type *type,
7073e30148cSDavid Howells 			    const char *description,
708a58946c1SDavid Howells 			    struct key_tag *domain_tag,
709028db3e2SLinus Torvalds 			    const char *callout_info)
7103e30148cSDavid Howells {
71176181c13SDavid Howells 	struct key *key;
7124a38e122SDavid Howells 	size_t callout_len = 0;
71376181c13SDavid Howells 	int ret;
71476181c13SDavid Howells 
7154a38e122SDavid Howells 	if (callout_info)
7164a38e122SDavid Howells 		callout_len = strlen(callout_info);
717a58946c1SDavid Howells 	key = request_key_and_link(type, description, domain_tag,
718a58946c1SDavid Howells 				   callout_info, callout_len,
719028db3e2SLinus Torvalds 				   NULL, NULL, KEY_ALLOC_IN_QUOTA);
72076181c13SDavid Howells 	if (!IS_ERR(key)) {
72176181c13SDavid Howells 		ret = wait_for_key_construction(key, false);
72276181c13SDavid Howells 		if (ret < 0) {
72376181c13SDavid Howells 			key_put(key);
72476181c13SDavid Howells 			return ERR_PTR(ret);
72576181c13SDavid Howells 		}
72676181c13SDavid Howells 	}
72776181c13SDavid Howells 	return key;
72876181c13SDavid Howells }
729a58946c1SDavid Howells EXPORT_SYMBOL(request_key_tag);
7304e54f085SDavid Howells 
731973c9f4fSDavid Howells /**
732973c9f4fSDavid Howells  * request_key_with_auxdata - Request a key with auxiliary data for the upcaller
733973c9f4fSDavid Howells  * @type: The type of key we want.
734973c9f4fSDavid Howells  * @description: The searchable description of the key.
735a58946c1SDavid Howells  * @domain_tag: The domain in which the key operates.
736973c9f4fSDavid Howells  * @callout_info: The data to pass to the instantiation upcall (or NULL).
737973c9f4fSDavid Howells  * @callout_len: The length of callout_info.
738973c9f4fSDavid Howells  * @aux: Auxiliary data for the upcall.
739973c9f4fSDavid Howells  *
740973c9f4fSDavid Howells  * As for request_key_and_link() except that it does not add the returned key
741973c9f4fSDavid Howells  * to a keyring if found and new keys are always allocated in the user's quota.
742973c9f4fSDavid Howells  *
743973c9f4fSDavid Howells  * Furthermore, it then works as wait_for_key_construction() to wait for the
744973c9f4fSDavid Howells  * completion of keys undergoing construction with a non-interruptible wait.
7454e54f085SDavid Howells  */
request_key_with_auxdata(struct key_type * type,const char * description,struct key_tag * domain_tag,const void * callout_info,size_t callout_len,void * aux)7464e54f085SDavid Howells struct key *request_key_with_auxdata(struct key_type *type,
7474e54f085SDavid Howells 				     const char *description,
748a58946c1SDavid Howells 				     struct key_tag *domain_tag,
7494a38e122SDavid Howells 				     const void *callout_info,
7504a38e122SDavid Howells 				     size_t callout_len,
751028db3e2SLinus Torvalds 				     void *aux)
7524e54f085SDavid Howells {
75376181c13SDavid Howells 	struct key *key;
75476181c13SDavid Howells 	int ret;
75576181c13SDavid Howells 
756a58946c1SDavid Howells 	key = request_key_and_link(type, description, domain_tag,
757a58946c1SDavid Howells 				   callout_info, callout_len,
758028db3e2SLinus Torvalds 				   aux, NULL, KEY_ALLOC_IN_QUOTA);
75976181c13SDavid Howells 	if (!IS_ERR(key)) {
76076181c13SDavid Howells 		ret = wait_for_key_construction(key, false);
76176181c13SDavid Howells 		if (ret < 0) {
76276181c13SDavid Howells 			key_put(key);
76376181c13SDavid Howells 			return ERR_PTR(ret);
76476181c13SDavid Howells 		}
76576181c13SDavid Howells 	}
76676181c13SDavid Howells 	return key;
76776181c13SDavid Howells }
76876181c13SDavid Howells EXPORT_SYMBOL(request_key_with_auxdata);
76976181c13SDavid Howells 
770896f1950SDavid Howells /**
771896f1950SDavid Howells  * request_key_rcu - Request key from RCU-read-locked context
772896f1950SDavid Howells  * @type: The type of key we want.
773896f1950SDavid Howells  * @description: The name of the key we want.
774a58946c1SDavid Howells  * @domain_tag: The domain in which the key operates.
775973c9f4fSDavid Howells  *
776896f1950SDavid Howells  * Request a key from a context that we may not sleep in (such as RCU-mode
777896f1950SDavid Howells  * pathwalk).  Keys under construction are ignored.
778973c9f4fSDavid Howells  *
779896f1950SDavid Howells  * Return a pointer to the found key if successful, -ENOKEY if we couldn't find
780896f1950SDavid Howells  * a key or some other error if the key found was unsuitable or inaccessible.
78176181c13SDavid Howells  */
request_key_rcu(struct key_type * type,const char * description,struct key_tag * domain_tag)782a58946c1SDavid Howells struct key *request_key_rcu(struct key_type *type,
783a58946c1SDavid Howells 			    const char *description,
784a58946c1SDavid Howells 			    struct key_tag *domain_tag)
78576181c13SDavid Howells {
786896f1950SDavid Howells 	struct keyring_search_context ctx = {
787896f1950SDavid Howells 		.index_key.type		= type,
788a58946c1SDavid Howells 		.index_key.domain_tag	= domain_tag,
789896f1950SDavid Howells 		.index_key.description	= description,
790896f1950SDavid Howells 		.index_key.desc_len	= strlen(description),
791896f1950SDavid Howells 		.cred			= current_cred(),
792896f1950SDavid Howells 		.match_data.cmp		= key_default_cmp,
793896f1950SDavid Howells 		.match_data.raw_data	= description,
794896f1950SDavid Howells 		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
795896f1950SDavid Howells 		.flags			= (KEYRING_SEARCH_DO_STATE_CHECK |
796896f1950SDavid Howells 					   KEYRING_SEARCH_SKIP_EXPIRED),
797896f1950SDavid Howells 	};
798896f1950SDavid Howells 	struct key *key;
799896f1950SDavid Howells 	key_ref_t key_ref;
80076181c13SDavid Howells 
801896f1950SDavid Howells 	kenter("%s,%s", type->name, description);
802896f1950SDavid Howells 
8037743c48eSDavid Howells 	key = check_cached_key(&ctx);
8047743c48eSDavid Howells 	if (key)
8057743c48eSDavid Howells 		return key;
8067743c48eSDavid Howells 
807896f1950SDavid Howells 	/* search all the process keyrings for a key */
808896f1950SDavid Howells 	key_ref = search_process_keyrings_rcu(&ctx);
809896f1950SDavid Howells 	if (IS_ERR(key_ref)) {
810896f1950SDavid Howells 		key = ERR_CAST(key_ref);
811896f1950SDavid Howells 		if (PTR_ERR(key_ref) == -EAGAIN)
812896f1950SDavid Howells 			key = ERR_PTR(-ENOKEY);
813896f1950SDavid Howells 	} else {
814896f1950SDavid Howells 		key = key_ref_to_ptr(key_ref);
8157743c48eSDavid Howells 		cache_requested_key(key);
81676181c13SDavid Howells 	}
817896f1950SDavid Howells 
818896f1950SDavid Howells 	kleave(" = %p", key);
819896f1950SDavid Howells 	return key;
820896f1950SDavid Howells }
821896f1950SDavid Howells EXPORT_SYMBOL(request_key_rcu);
822