18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Request key authorisation token key definition. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * See Documentation/security/keys/request-key.rst 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/sched.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 158c2ecf20Sopenharmony_ci#include "internal.h" 168c2ecf20Sopenharmony_ci#include <keys/request_key_auth-type.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic int request_key_auth_preparse(struct key_preparsed_payload *); 198c2ecf20Sopenharmony_cistatic void request_key_auth_free_preparse(struct key_preparsed_payload *); 208c2ecf20Sopenharmony_cistatic int request_key_auth_instantiate(struct key *, 218c2ecf20Sopenharmony_ci struct key_preparsed_payload *); 228c2ecf20Sopenharmony_cistatic void request_key_auth_describe(const struct key *, struct seq_file *); 238c2ecf20Sopenharmony_cistatic void request_key_auth_revoke(struct key *); 248c2ecf20Sopenharmony_cistatic void request_key_auth_destroy(struct key *); 258c2ecf20Sopenharmony_cistatic long request_key_auth_read(const struct key *, char *, size_t); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * The request-key authorisation key type definition. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistruct key_type key_type_request_key_auth = { 318c2ecf20Sopenharmony_ci .name = ".request_key_auth", 328c2ecf20Sopenharmony_ci .def_datalen = sizeof(struct request_key_auth), 338c2ecf20Sopenharmony_ci .preparse = request_key_auth_preparse, 348c2ecf20Sopenharmony_ci .free_preparse = request_key_auth_free_preparse, 358c2ecf20Sopenharmony_ci .instantiate = request_key_auth_instantiate, 368c2ecf20Sopenharmony_ci .describe = request_key_auth_describe, 378c2ecf20Sopenharmony_ci .revoke = request_key_auth_revoke, 388c2ecf20Sopenharmony_ci .destroy = request_key_auth_destroy, 398c2ecf20Sopenharmony_ci .read = request_key_auth_read, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int request_key_auth_preparse(struct key_preparsed_payload *prep) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic void request_key_auth_free_preparse(struct key_preparsed_payload *prep) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * Instantiate a request-key authorisation key. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistatic int request_key_auth_instantiate(struct key *key, 558c2ecf20Sopenharmony_ci struct key_preparsed_payload *prep) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci rcu_assign_keypointer(key, (struct request_key_auth *)prep->data); 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * Describe an authorisation token. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistatic void request_key_auth_describe(const struct key *key, 658c2ecf20Sopenharmony_ci struct seq_file *m) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci struct request_key_auth *rka = dereference_key_rcu(key); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!rka) 708c2ecf20Sopenharmony_ci return; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci seq_puts(m, "key:"); 738c2ecf20Sopenharmony_ci seq_puts(m, key->description); 748c2ecf20Sopenharmony_ci if (key_is_positive(key)) 758c2ecf20Sopenharmony_ci seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* 798c2ecf20Sopenharmony_ci * Read the callout_info data (retrieves the callout information). 808c2ecf20Sopenharmony_ci * - the key's semaphore is read-locked 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_cistatic long request_key_auth_read(const struct key *key, 838c2ecf20Sopenharmony_ci char *buffer, size_t buflen) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct request_key_auth *rka = dereference_key_locked(key); 868c2ecf20Sopenharmony_ci size_t datalen; 878c2ecf20Sopenharmony_ci long ret; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (!rka) 908c2ecf20Sopenharmony_ci return -EKEYREVOKED; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci datalen = rka->callout_len; 938c2ecf20Sopenharmony_ci ret = datalen; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* we can return the data as is */ 968c2ecf20Sopenharmony_ci if (buffer && buflen > 0) { 978c2ecf20Sopenharmony_ci if (buflen > datalen) 988c2ecf20Sopenharmony_ci buflen = datalen; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci memcpy(buffer, rka->callout_info, buflen); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return ret; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void free_request_key_auth(struct request_key_auth *rka) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if (!rka) 1098c2ecf20Sopenharmony_ci return; 1108c2ecf20Sopenharmony_ci key_put(rka->target_key); 1118c2ecf20Sopenharmony_ci key_put(rka->dest_keyring); 1128c2ecf20Sopenharmony_ci if (rka->cred) 1138c2ecf20Sopenharmony_ci put_cred(rka->cred); 1148c2ecf20Sopenharmony_ci kfree(rka->callout_info); 1158c2ecf20Sopenharmony_ci kfree(rka); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * Dispose of the request_key_auth record under RCU conditions 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistatic void request_key_auth_rcu_disposal(struct rcu_head *rcu) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct request_key_auth *rka = 1248c2ecf20Sopenharmony_ci container_of(rcu, struct request_key_auth, rcu); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci free_request_key_auth(rka); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* 1308c2ecf20Sopenharmony_ci * Handle revocation of an authorisation token key. 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * Called with the key sem write-locked. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic void request_key_auth_revoke(struct key *key) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct request_key_auth *rka = dereference_key_locked(key); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci kenter("{%d}", key->serial); 1398c2ecf20Sopenharmony_ci rcu_assign_keypointer(key, NULL); 1408c2ecf20Sopenharmony_ci call_rcu(&rka->rcu, request_key_auth_rcu_disposal); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * Destroy an instantiation authorisation token key. 1458c2ecf20Sopenharmony_ci */ 1468c2ecf20Sopenharmony_cistatic void request_key_auth_destroy(struct key *key) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct request_key_auth *rka = rcu_access_pointer(key->payload.rcu_data0); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci kenter("{%d}", key->serial); 1518c2ecf20Sopenharmony_ci if (rka) { 1528c2ecf20Sopenharmony_ci rcu_assign_keypointer(key, NULL); 1538c2ecf20Sopenharmony_ci call_rcu(&rka->rcu, request_key_auth_rcu_disposal); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/* 1588c2ecf20Sopenharmony_ci * Create an authorisation token for /sbin/request-key or whoever to gain 1598c2ecf20Sopenharmony_ci * access to the caller's security data. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_cistruct key *request_key_auth_new(struct key *target, const char *op, 1628c2ecf20Sopenharmony_ci const void *callout_info, size_t callout_len, 1638c2ecf20Sopenharmony_ci struct key *dest_keyring) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct request_key_auth *rka, *irka; 1668c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 1678c2ecf20Sopenharmony_ci struct key *authkey = NULL; 1688c2ecf20Sopenharmony_ci char desc[20]; 1698c2ecf20Sopenharmony_ci int ret = -ENOMEM; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci kenter("%d,", target->serial); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* allocate a auth record */ 1748c2ecf20Sopenharmony_ci rka = kzalloc(sizeof(*rka), GFP_KERNEL); 1758c2ecf20Sopenharmony_ci if (!rka) 1768c2ecf20Sopenharmony_ci goto error; 1778c2ecf20Sopenharmony_ci rka->callout_info = kmemdup(callout_info, callout_len, GFP_KERNEL); 1788c2ecf20Sopenharmony_ci if (!rka->callout_info) 1798c2ecf20Sopenharmony_ci goto error_free_rka; 1808c2ecf20Sopenharmony_ci rka->callout_len = callout_len; 1818c2ecf20Sopenharmony_ci strlcpy(rka->op, op, sizeof(rka->op)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* see if the calling process is already servicing the key request of 1848c2ecf20Sopenharmony_ci * another process */ 1858c2ecf20Sopenharmony_ci if (cred->request_key_auth) { 1868c2ecf20Sopenharmony_ci /* it is - use that instantiation context here too */ 1878c2ecf20Sopenharmony_ci down_read(&cred->request_key_auth->sem); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* if the auth key has been revoked, then the key we're 1908c2ecf20Sopenharmony_ci * servicing is already instantiated */ 1918c2ecf20Sopenharmony_ci if (test_bit(KEY_FLAG_REVOKED, 1928c2ecf20Sopenharmony_ci &cred->request_key_auth->flags)) { 1938c2ecf20Sopenharmony_ci up_read(&cred->request_key_auth->sem); 1948c2ecf20Sopenharmony_ci ret = -EKEYREVOKED; 1958c2ecf20Sopenharmony_ci goto error_free_rka; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci irka = cred->request_key_auth->payload.data[0]; 1998c2ecf20Sopenharmony_ci rka->cred = get_cred(irka->cred); 2008c2ecf20Sopenharmony_ci rka->pid = irka->pid; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci up_read(&cred->request_key_auth->sem); 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci else { 2058c2ecf20Sopenharmony_ci /* it isn't - use this process as the context */ 2068c2ecf20Sopenharmony_ci rka->cred = get_cred(cred); 2078c2ecf20Sopenharmony_ci rka->pid = current->pid; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci rka->target_key = key_get(target); 2118c2ecf20Sopenharmony_ci rka->dest_keyring = key_get(dest_keyring); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* allocate the auth key */ 2148c2ecf20Sopenharmony_ci sprintf(desc, "%x", target->serial); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci authkey = key_alloc(&key_type_request_key_auth, desc, 2178c2ecf20Sopenharmony_ci cred->fsuid, cred->fsgid, cred, 2188c2ecf20Sopenharmony_ci KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | KEY_POS_LINK | 2198c2ecf20Sopenharmony_ci KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL); 2208c2ecf20Sopenharmony_ci if (IS_ERR(authkey)) { 2218c2ecf20Sopenharmony_ci ret = PTR_ERR(authkey); 2228c2ecf20Sopenharmony_ci goto error_free_rka; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* construct the auth key */ 2268c2ecf20Sopenharmony_ci ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); 2278c2ecf20Sopenharmony_ci if (ret < 0) 2288c2ecf20Sopenharmony_ci goto error_put_authkey; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci kleave(" = {%d,%d}", authkey->serial, refcount_read(&authkey->usage)); 2318c2ecf20Sopenharmony_ci return authkey; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cierror_put_authkey: 2348c2ecf20Sopenharmony_ci key_put(authkey); 2358c2ecf20Sopenharmony_cierror_free_rka: 2368c2ecf20Sopenharmony_ci free_request_key_auth(rka); 2378c2ecf20Sopenharmony_cierror: 2388c2ecf20Sopenharmony_ci kleave("= %d", ret); 2398c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* 2438c2ecf20Sopenharmony_ci * Search the current process's keyrings for the authorisation key for 2448c2ecf20Sopenharmony_ci * instantiation of a key. 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cistruct key *key_get_instantiation_authkey(key_serial_t target_id) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci char description[16]; 2498c2ecf20Sopenharmony_ci struct keyring_search_context ctx = { 2508c2ecf20Sopenharmony_ci .index_key.type = &key_type_request_key_auth, 2518c2ecf20Sopenharmony_ci .index_key.description = description, 2528c2ecf20Sopenharmony_ci .cred = current_cred(), 2538c2ecf20Sopenharmony_ci .match_data.cmp = key_default_cmp, 2548c2ecf20Sopenharmony_ci .match_data.raw_data = description, 2558c2ecf20Sopenharmony_ci .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, 2568c2ecf20Sopenharmony_ci .flags = (KEYRING_SEARCH_DO_STATE_CHECK | 2578c2ecf20Sopenharmony_ci KEYRING_SEARCH_RECURSE), 2588c2ecf20Sopenharmony_ci }; 2598c2ecf20Sopenharmony_ci struct key *authkey; 2608c2ecf20Sopenharmony_ci key_ref_t authkey_ref; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ctx.index_key.desc_len = sprintf(description, "%x", target_id); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci rcu_read_lock(); 2658c2ecf20Sopenharmony_ci authkey_ref = search_process_keyrings_rcu(&ctx); 2668c2ecf20Sopenharmony_ci rcu_read_unlock(); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (IS_ERR(authkey_ref)) { 2698c2ecf20Sopenharmony_ci authkey = ERR_CAST(authkey_ref); 2708c2ecf20Sopenharmony_ci if (authkey == ERR_PTR(-EAGAIN)) 2718c2ecf20Sopenharmony_ci authkey = ERR_PTR(-ENOKEY); 2728c2ecf20Sopenharmony_ci goto error; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci authkey = key_ref_to_ptr(authkey_ref); 2768c2ecf20Sopenharmony_ci if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { 2778c2ecf20Sopenharmony_ci key_put(authkey); 2788c2ecf20Sopenharmony_ci authkey = ERR_PTR(-EKEYREVOKED); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cierror: 2828c2ecf20Sopenharmony_ci return authkey; 2838c2ecf20Sopenharmony_ci} 284