// SPDX-License-Identifier: GPL-2.0-or-later /* Request a key from userspace * * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * See Documentation/security/keys/request-key.rst
*/
/* Do not cache key if it is a kernel thread */ if (!(t->flags & PF_KTHREAD)) {
key_put(t->cached_requested_key);
t->cached_requested_key = key_get(key);
set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
} #endif
}
/** * complete_request_key - Complete the construction of a key. * @authkey: The authorisation key. * @error: The success or failute of the construction. * * Complete the attempt to construct a key. The key will be negated * if an error is indicated. The authorisation key will be revoked * unconditionally.
*/ void complete_request_key(struct key *authkey, int error)
{ struct request_key_auth *rka = get_request_key_auth(authkey); struct key *key = rka->target_key;
/* * Initialise a usermode helper that is going to have a specific session * keyring. * * This is called in context of freshly forked kthread before kernel_execve(), * so we can simply install the desired session_keyring at this point.
*/ staticint umh_keys_init(struct subprocess_info *info, struct cred *cred)
{ struct key *keyring = info->data;
/* attach the auth key to the session keyring */
ret = key_link(keyring, authkey); if (ret < 0) goto error_link;
/* record the UID and GID */
sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid));
sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid));
/* we say which key is under construction */
sprintf(key_str, "%d", key->serial);
/* we specify the process's default keyrings */
sprintf(keyring_str[0], "%d",
cred->thread_keyring ? cred->thread_keyring->serial : 0);
/* set up a minimal environment */
i = 0;
envp[i++] = "HOME=/";
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[i] = NULL;
/* set up the argument list */
i = 0;
argv[i++] = (char *)request_key;
argv[i++] = (char *)rka->op;
argv[i++] = key_str;
argv[i++] = uid_str;
argv[i++] = gid_str;
argv[i++] = keyring_str[0];
argv[i++] = keyring_str[1];
argv[i++] = keyring_str[2];
argv[i] = NULL;
/* do it */
ret = call_usermodehelper_keys(request_key, argv, envp, keyring,
UMH_WAIT_PROC);
kdebug("usermode -> 0x%x", ret); if (ret >= 0) { /* ret is the exit/wait code */ if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) ||
key_validate(key) < 0)
ret = -ENOKEY; else /* ignore any errors from userspace if the key was
* instantiated */
ret = 0;
}
/* allocate an authorisation key */
authkey = request_key_auth_new(key, "create", callout_info, callout_len,
dest_keyring); if (IS_ERR(authkey)) return PTR_ERR(authkey);
/* Make the call */
actor = call_sbin_request_key; if (key->type->request_key)
actor = key->type->request_key;
ret = actor(authkey, aux);
/* check that the actor called complete_request_key() prior to
* returning an error */
WARN_ON(ret < 0 &&
!test_bit(KEY_FLAG_INVALIDATED, &authkey->flags));
/* * Get the appropriate destination keyring for the request. * * The keyring selected is returned with an extra reference upon it which the * caller must release.
*/ staticint construct_get_dest_keyring(struct key **_dest_keyring)
{ struct request_key_auth *rka; conststruct cred *cred = current_cred(); struct key *dest_keyring = *_dest_keyring, *authkey; int ret;
kenter("%p", dest_keyring);
/* find the appropriate keyring */ if (dest_keyring) { /* the caller supplied one */
key_get(dest_keyring);
} else { bool do_perm_check = true;
/* use a default keyring; falling through the cases until we
* find one that we actually have */ switch (cred->jit_keyring) { case KEY_REQKEY_DEFL_DEFAULT: case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: if (cred->request_key_auth) {
authkey = cred->request_key_auth;
down_read(&authkey->sem);
rka = get_request_key_auth(authkey); if (!test_bit(KEY_FLAG_REVOKED,
&authkey->flags))
dest_keyring =
key_get(rka->dest_keyring);
up_read(&authkey->sem); if (dest_keyring) {
do_perm_check = false; break;
}
}
fallthrough; case KEY_REQKEY_DEFL_THREAD_KEYRING:
dest_keyring = key_get(cred->thread_keyring); if (dest_keyring) break;
fallthrough; case KEY_REQKEY_DEFL_PROCESS_KEYRING:
dest_keyring = key_get(cred->process_keyring); if (dest_keyring) break;
fallthrough; case KEY_REQKEY_DEFL_SESSION_KEYRING:
dest_keyring = key_get(cred->session_keyring);
if (dest_keyring) break;
fallthrough; case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
ret = look_up_user_keyrings(NULL, &dest_keyring); if (ret < 0) return ret; break;
case KEY_REQKEY_DEFL_USER_KEYRING:
ret = look_up_user_keyrings(&dest_keyring, NULL); if (ret < 0) return ret; break;
case KEY_REQKEY_DEFL_GROUP_KEYRING: default:
BUG();
}
/* * Require Write permission on the keyring. This is essential * because the default keyring may be the session keyring, and * joining a keyring only requires Search permission. * * However, this check is skipped for the "requestor keyring" so * that /sbin/request-key can itself use request_key() to add * keys to the original requestor's destination keyring.
*/ if (dest_keyring && do_perm_check) {
ret = key_permission(make_key_ref(dest_keyring, 1),
KEY_NEED_WRITE); if (ret) {
key_put(dest_keyring); return ret;
}
}
}
/* * Allocate a new key in under-construction state and attempt to link it in to * the requested keyring. * * May return a key that's already under construction instead if there was a * race between two thread calling request_key().
*/ staticint construct_alloc_key(struct keyring_search_context *ctx, struct key *dest_keyring, unsignedlong flags, struct key_user *user, struct key **_key)
{ struct assoc_array_edit *edit = NULL; struct key *key;
key_perm_t perm;
key_ref_t key_ref; int ret;
if (dest_keyring) {
ret = __key_link_lock(dest_keyring, &key->index_key); if (ret < 0) goto link_lock_failed;
}
/* * Attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we * waited for locks. * * The caller might specify a comparison function which looks for keys * that do not exactly match but are still equivalent from the caller's * perspective. The __key_link_begin() operation must be done only after * an actual key is determined.
*/
mutex_lock(&key_construction_mutex);
rcu_read_lock();
key_ref = search_process_keyrings_rcu(ctx);
rcu_read_unlock(); if (!IS_ERR(key_ref)) goto key_already_present;
if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &key->index_key, &edit); if (ret < 0) goto link_alloc_failed;
__key_link(dest_keyring, key, &edit);
}
/* the key is now present - we tell the caller that we found it by
* returning -EINPROGRESS */
key_already_present:
key_put(key);
mutex_unlock(&key_construction_mutex);
key = key_ref_to_ptr(key_ref); if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &key->index_key, &edit); if (ret < 0) goto link_alloc_failed_unlocked;
ret = __key_link_check_live_key(dest_keyring, key); if (ret == 0)
__key_link(dest_keyring, key, &edit);
__key_link_end(dest_keyring, &key->index_key, edit); if (ret < 0) goto link_check_failed;
}
mutex_unlock(&user->cons_lock);
*_key = key;
kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS;
/** * request_key_and_link - Request a key and cache it in a keyring. * @type: The type of key we want. * @description: The searchable description of the key. * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * * A key matching the specified criteria (type, description, domain_tag) is * searched for in the process's keyrings and returned with its usage count * incremented if found. Otherwise, if callout_info is not NULL, a key will be * allocated and some service (probably in userspace) will be asked to * instantiate it. * * If successfully found or created, the key will be linked to the destination * keyring if one is provided. * * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT * if insufficient key quota was available to create a new key; or -ENOMEM if * insufficient memory was available. * * If the returned key was created, then it may still be under construction, * and wait_for_key_construction() should be used to wait for that to complete.
*/ struct key *request_key_and_link(struct key_type *type, constchar *description, struct key_tag *domain_tag, constvoid *callout_info,
size_t callout_len, void *aux, struct key *dest_keyring, unsignedlong flags)
{ struct keyring_search_context ctx = {
.index_key.type = type,
.index_key.domain_tag = domain_tag,
.index_key.description = description,
.index_key.desc_len = strlen(description),
.cred = current_cred(),
.match_data.cmp = key_default_cmp,
.match_data.raw_data = description,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.flags = (KEYRING_SEARCH_DO_STATE_CHECK |
KEYRING_SEARCH_SKIP_EXPIRED |
KEYRING_SEARCH_RECURSE),
}; struct key *key;
key_ref_t key_ref; int ret;
if (type->match_preparse) {
ret = type->match_preparse(&ctx.match_data); if (ret < 0) {
key = ERR_PTR(ret); goto error;
}
}
key = check_cached_key(&ctx); if (key) goto error_free;
/* search all the process keyrings for a key */
rcu_read_lock();
key_ref = search_process_keyrings_rcu(&ctx);
rcu_read_unlock();
if (!IS_ERR(key_ref)) { if (dest_keyring) {
ret = key_task_permission(key_ref, current_cred(),
KEY_NEED_LINK); if (ret < 0) {
key_ref_put(key_ref);
key = ERR_PTR(ret); goto error_free;
}
}
key = key_ref_to_ptr(key_ref); if (dest_keyring) {
ret = key_link(dest_keyring, key); if (ret < 0) {
key_put(key);
key = ERR_PTR(ret); goto error_free;
}
}
/* Only cache the key on immediate success */
cache_requested_key(key);
} elseif (PTR_ERR(key_ref) != -EAGAIN) {
key = ERR_CAST(key_ref);
} else { /* the search failed, but the keyrings were searchable, so we
* should consult userspace if we can */
key = ERR_PTR(-ENOKEY); if (!callout_info) goto error_free;
/** * wait_for_key_construction - Wait for construction of a key to complete * @key: The key being waited for. * @intr: Whether to wait interruptibly. * * Wait for a key to finish being constructed. * * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was * revoked or expired.
*/ int wait_for_key_construction(struct key *key, bool intr)
{ int ret;
ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT,
intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (ret) return -ERESTARTSYS;
ret = key_read_state(key); if (ret < 0) return ret; return key_validate(key);
}
EXPORT_SYMBOL(wait_for_key_construction);
/** * request_key_tag - Request a key and wait for construction * @type: Type of key. * @description: The searchable description of the key. * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found, new keys are always allocated in the user's quota, * the callout_info must be a NUL-terminated string and no auxiliary data can * be passed. * * Furthermore, it then works as wait_for_key_construction() to wait for the * completion of keys undergoing construction with a non-interruptible wait.
*/ struct key *request_key_tag(struct key_type *type, constchar *description, struct key_tag *domain_tag, constchar *callout_info)
{ struct key *key;
size_t callout_len = 0; int ret;
if (callout_info)
callout_len = strlen(callout_info);
key = request_key_and_link(type, description, domain_tag,
callout_info, callout_len,
NULL, NULL, KEY_ALLOC_IN_QUOTA); if (!IS_ERR(key)) {
ret = wait_for_key_construction(key, false); if (ret < 0) {
key_put(key); return ERR_PTR(ret);
}
} return key;
}
EXPORT_SYMBOL(request_key_tag);
/** * request_key_with_auxdata - Request a key with auxiliary data for the upcaller * @type: The type of key we want. * @description: The searchable description of the key. * @domain_tag: The domain in which the key operates. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found and new keys are always allocated in the user's quota. * * Furthermore, it then works as wait_for_key_construction() to wait for the * completion of keys undergoing construction with a non-interruptible wait.
*/ struct key *request_key_with_auxdata(struct key_type *type, constchar *description, struct key_tag *domain_tag, constvoid *callout_info,
size_t callout_len, void *aux)
{ struct key *key; int ret;
/** * request_key_rcu - Request key from RCU-read-locked context * @type: The type of key we want. * @description: The name of the key we want. * @domain_tag: The domain in which the key operates. * * Request a key from a context that we may not sleep in (such as RCU-mode * pathwalk). Keys under construction are ignored. * * Return a pointer to the found key if successful, -ENOKEY if we couldn't find * a key or some other error if the key found was unsuitable or inaccessible.
*/ struct key *request_key_rcu(struct key_type *type, constchar *description, struct key_tag *domain_tag)
{ struct keyring_search_context ctx = {
.index_key.type = type,
.index_key.domain_tag = domain_tag,
.index_key.description = description,
.index_key.desc_len = strlen(description),
.cred = current_cred(),
.match_data.cmp = key_default_cmp,
.match_data.raw_data = description,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.flags = (KEYRING_SEARCH_DO_STATE_CHECK |
KEYRING_SEARCH_SKIP_EXPIRED),
}; struct key *key;
key_ref_t key_ref;
kenter("%s,%s", type->name, description);
key = check_cached_key(&ctx); if (key) return key;
/* search all the process keyrings for a key */
key_ref = search_process_keyrings_rcu(&ctx); if (IS_ERR(key_ref)) {
key = ERR_CAST(key_ref); if (PTR_ERR(key_ref) == -EAGAIN)
key = ERR_PTR(-ENOKEY);
} else {
key = key_ref_to_ptr(key_ref);
cache_requested_key(key);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.