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