162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* Request key authorisation token key definition. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2005 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/sched.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/seq_file.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/uaccess.h> 1562306a36Sopenharmony_ci#include "internal.h" 1662306a36Sopenharmony_ci#include <keys/request_key_auth-type.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic int request_key_auth_preparse(struct key_preparsed_payload *); 1962306a36Sopenharmony_cistatic void request_key_auth_free_preparse(struct key_preparsed_payload *); 2062306a36Sopenharmony_cistatic int request_key_auth_instantiate(struct key *, 2162306a36Sopenharmony_ci struct key_preparsed_payload *); 2262306a36Sopenharmony_cistatic void request_key_auth_describe(const struct key *, struct seq_file *); 2362306a36Sopenharmony_cistatic void request_key_auth_revoke(struct key *); 2462306a36Sopenharmony_cistatic void request_key_auth_destroy(struct key *); 2562306a36Sopenharmony_cistatic long request_key_auth_read(const struct key *, char *, size_t); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * The request-key authorisation key type definition. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistruct key_type key_type_request_key_auth = { 3162306a36Sopenharmony_ci .name = ".request_key_auth", 3262306a36Sopenharmony_ci .def_datalen = sizeof(struct request_key_auth), 3362306a36Sopenharmony_ci .preparse = request_key_auth_preparse, 3462306a36Sopenharmony_ci .free_preparse = request_key_auth_free_preparse, 3562306a36Sopenharmony_ci .instantiate = request_key_auth_instantiate, 3662306a36Sopenharmony_ci .describe = request_key_auth_describe, 3762306a36Sopenharmony_ci .revoke = request_key_auth_revoke, 3862306a36Sopenharmony_ci .destroy = request_key_auth_destroy, 3962306a36Sopenharmony_ci .read = request_key_auth_read, 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic int request_key_auth_preparse(struct key_preparsed_payload *prep) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci return 0; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic void request_key_auth_free_preparse(struct key_preparsed_payload *prep) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* 5262306a36Sopenharmony_ci * Instantiate a request-key authorisation key. 5362306a36Sopenharmony_ci */ 5462306a36Sopenharmony_cistatic int request_key_auth_instantiate(struct key *key, 5562306a36Sopenharmony_ci struct key_preparsed_payload *prep) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci rcu_assign_keypointer(key, (struct request_key_auth *)prep->data); 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Describe an authorisation token. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistatic void request_key_auth_describe(const struct key *key, 6562306a36Sopenharmony_ci struct seq_file *m) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct request_key_auth *rka = dereference_key_rcu(key); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci if (!rka) 7062306a36Sopenharmony_ci return; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci seq_puts(m, "key:"); 7362306a36Sopenharmony_ci seq_puts(m, key->description); 7462306a36Sopenharmony_ci if (key_is_positive(key)) 7562306a36Sopenharmony_ci seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* 7962306a36Sopenharmony_ci * Read the callout_info data (retrieves the callout information). 8062306a36Sopenharmony_ci * - the key's semaphore is read-locked 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic long request_key_auth_read(const struct key *key, 8362306a36Sopenharmony_ci char *buffer, size_t buflen) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct request_key_auth *rka = dereference_key_locked(key); 8662306a36Sopenharmony_ci size_t datalen; 8762306a36Sopenharmony_ci long ret; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (!rka) 9062306a36Sopenharmony_ci return -EKEYREVOKED; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci datalen = rka->callout_len; 9362306a36Sopenharmony_ci ret = datalen; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* we can return the data as is */ 9662306a36Sopenharmony_ci if (buffer && buflen > 0) { 9762306a36Sopenharmony_ci if (buflen > datalen) 9862306a36Sopenharmony_ci buflen = datalen; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci memcpy(buffer, rka->callout_info, buflen); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return ret; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic void free_request_key_auth(struct request_key_auth *rka) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci if (!rka) 10962306a36Sopenharmony_ci return; 11062306a36Sopenharmony_ci key_put(rka->target_key); 11162306a36Sopenharmony_ci key_put(rka->dest_keyring); 11262306a36Sopenharmony_ci if (rka->cred) 11362306a36Sopenharmony_ci put_cred(rka->cred); 11462306a36Sopenharmony_ci kfree(rka->callout_info); 11562306a36Sopenharmony_ci kfree(rka); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* 11962306a36Sopenharmony_ci * Dispose of the request_key_auth record under RCU conditions 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistatic void request_key_auth_rcu_disposal(struct rcu_head *rcu) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct request_key_auth *rka = 12462306a36Sopenharmony_ci container_of(rcu, struct request_key_auth, rcu); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci free_request_key_auth(rka); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * Handle revocation of an authorisation token key. 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * Called with the key sem write-locked. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistatic void request_key_auth_revoke(struct key *key) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct request_key_auth *rka = dereference_key_locked(key); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci kenter("{%d}", key->serial); 13962306a36Sopenharmony_ci rcu_assign_keypointer(key, NULL); 14062306a36Sopenharmony_ci call_rcu(&rka->rcu, request_key_auth_rcu_disposal); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Destroy an instantiation authorisation token key. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic void request_key_auth_destroy(struct key *key) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci kenter("{%d}", key->serial); 15162306a36Sopenharmony_ci if (rka) { 15262306a36Sopenharmony_ci rcu_assign_keypointer(key, NULL); 15362306a36Sopenharmony_ci call_rcu(&rka->rcu, request_key_auth_rcu_disposal); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci/* 15862306a36Sopenharmony_ci * Create an authorisation token for /sbin/request-key or whoever to gain 15962306a36Sopenharmony_ci * access to the caller's security data. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_cistruct key *request_key_auth_new(struct key *target, const char *op, 16262306a36Sopenharmony_ci const void *callout_info, size_t callout_len, 16362306a36Sopenharmony_ci struct key *dest_keyring) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct request_key_auth *rka, *irka; 16662306a36Sopenharmony_ci const struct cred *cred = current_cred(); 16762306a36Sopenharmony_ci struct key *authkey = NULL; 16862306a36Sopenharmony_ci char desc[20]; 16962306a36Sopenharmony_ci int ret = -ENOMEM; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci kenter("%d,", target->serial); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* allocate a auth record */ 17462306a36Sopenharmony_ci rka = kzalloc(sizeof(*rka), GFP_KERNEL); 17562306a36Sopenharmony_ci if (!rka) 17662306a36Sopenharmony_ci goto error; 17762306a36Sopenharmony_ci rka->callout_info = kmemdup(callout_info, callout_len, GFP_KERNEL); 17862306a36Sopenharmony_ci if (!rka->callout_info) 17962306a36Sopenharmony_ci goto error_free_rka; 18062306a36Sopenharmony_ci rka->callout_len = callout_len; 18162306a36Sopenharmony_ci strscpy(rka->op, op, sizeof(rka->op)); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci /* see if the calling process is already servicing the key request of 18462306a36Sopenharmony_ci * another process */ 18562306a36Sopenharmony_ci if (cred->request_key_auth) { 18662306a36Sopenharmony_ci /* it is - use that instantiation context here too */ 18762306a36Sopenharmony_ci down_read(&cred->request_key_auth->sem); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* if the auth key has been revoked, then the key we're 19062306a36Sopenharmony_ci * servicing is already instantiated */ 19162306a36Sopenharmony_ci if (test_bit(KEY_FLAG_REVOKED, 19262306a36Sopenharmony_ci &cred->request_key_auth->flags)) { 19362306a36Sopenharmony_ci up_read(&cred->request_key_auth->sem); 19462306a36Sopenharmony_ci ret = -EKEYREVOKED; 19562306a36Sopenharmony_ci goto error_free_rka; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci irka = cred->request_key_auth->payload.data[0]; 19962306a36Sopenharmony_ci rka->cred = get_cred(irka->cred); 20062306a36Sopenharmony_ci rka->pid = irka->pid; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci up_read(&cred->request_key_auth->sem); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci else { 20562306a36Sopenharmony_ci /* it isn't - use this process as the context */ 20662306a36Sopenharmony_ci rka->cred = get_cred(cred); 20762306a36Sopenharmony_ci rka->pid = current->pid; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci rka->target_key = key_get(target); 21162306a36Sopenharmony_ci rka->dest_keyring = key_get(dest_keyring); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* allocate the auth key */ 21462306a36Sopenharmony_ci sprintf(desc, "%x", target->serial); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci authkey = key_alloc(&key_type_request_key_auth, desc, 21762306a36Sopenharmony_ci cred->fsuid, cred->fsgid, cred, 21862306a36Sopenharmony_ci KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_POS_LINK | 21962306a36Sopenharmony_ci KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); 22062306a36Sopenharmony_ci if (IS_ERR(authkey)) { 22162306a36Sopenharmony_ci ret = PTR_ERR(authkey); 22262306a36Sopenharmony_ci goto error_free_rka; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* construct the auth key */ 22662306a36Sopenharmony_ci ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); 22762306a36Sopenharmony_ci if (ret < 0) 22862306a36Sopenharmony_ci goto error_put_authkey; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); 23162306a36Sopenharmony_ci return authkey; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cierror_put_authkey: 23462306a36Sopenharmony_ci key_put(authkey); 23562306a36Sopenharmony_cierror_free_rka: 23662306a36Sopenharmony_ci free_request_key_auth(rka); 23762306a36Sopenharmony_cierror: 23862306a36Sopenharmony_ci kleave("= %d", ret); 23962306a36Sopenharmony_ci return ERR_PTR(ret); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* 24362306a36Sopenharmony_ci * Search the current process's keyrings for the authorisation key for 24462306a36Sopenharmony_ci * instantiation of a key. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_cistruct key *key_get_instantiation_authkey(key_serial_t target_id) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci char description[16]; 24962306a36Sopenharmony_ci struct keyring_search_context ctx = { 25062306a36Sopenharmony_ci .index_key.type = &key_type_request_key_auth, 25162306a36Sopenharmony_ci .index_key.description = description, 25262306a36Sopenharmony_ci .cred = current_cred(), 25362306a36Sopenharmony_ci .match_data.cmp = key_default_cmp, 25462306a36Sopenharmony_ci .match_data.raw_data = description, 25562306a36Sopenharmony_ci .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, 25662306a36Sopenharmony_ci .flags = (KEYRING_SEARCH_DO_STATE_CHECK | 25762306a36Sopenharmony_ci KEYRING_SEARCH_RECURSE), 25862306a36Sopenharmony_ci }; 25962306a36Sopenharmony_ci struct key *authkey; 26062306a36Sopenharmony_ci key_ref_t authkey_ref; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci ctx.index_key.desc_len = sprintf(description, "%x", target_id); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci rcu_read_lock(); 26562306a36Sopenharmony_ci authkey_ref = search_process_keyrings_rcu(&ctx); 26662306a36Sopenharmony_ci rcu_read_unlock(); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (IS_ERR(authkey_ref)) { 26962306a36Sopenharmony_ci authkey = ERR_CAST(authkey_ref); 27062306a36Sopenharmony_ci if (authkey == ERR_PTR(-EAGAIN)) 27162306a36Sopenharmony_ci authkey = ERR_PTR(-ENOKEY); 27262306a36Sopenharmony_ci goto error; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci authkey = key_ref_to_ptr(authkey_ref); 27662306a36Sopenharmony_ci if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { 27762306a36Sopenharmony_ci key_put(authkey); 27862306a36Sopenharmony_ci authkey = ERR_PTR(-EKEYREVOKED); 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cierror: 28262306a36Sopenharmony_ci return authkey; 28362306a36Sopenharmony_ci} 284