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