18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Basic authentication token and access key management 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/export.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/poison.h> 118c2ecf20Sopenharmony_ci#include <linux/sched.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/security.h> 148c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 158c2ecf20Sopenharmony_ci#include <linux/random.h> 168c2ecf20Sopenharmony_ci#include <linux/ima.h> 178c2ecf20Sopenharmony_ci#include <linux/err.h> 188c2ecf20Sopenharmony_ci#include "internal.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct kmem_cache *key_jar; 218c2ecf20Sopenharmony_cistruct rb_root key_serial_tree; /* tree of keys indexed by serial */ 228c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(key_serial_lock); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct rb_root key_user_tree; /* tree of quota records indexed by UID */ 258c2ecf20Sopenharmony_ciDEFINE_SPINLOCK(key_user_lock); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ciunsigned int key_quota_root_maxkeys = 1000000; /* root's key count quota */ 288c2ecf20Sopenharmony_ciunsigned int key_quota_root_maxbytes = 25000000; /* root's key space quota */ 298c2ecf20Sopenharmony_ciunsigned int key_quota_maxkeys = 200; /* general key count quota */ 308c2ecf20Sopenharmony_ciunsigned int key_quota_maxbytes = 20000; /* general key space quota */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic LIST_HEAD(key_types_list); 338c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(key_types_sem); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* We serialise key instantiation and link */ 368c2ecf20Sopenharmony_ciDEFINE_MUTEX(key_construction_mutex); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#ifdef KEY_DEBUGGING 398c2ecf20Sopenharmony_civoid __key_check(const struct key *key) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci printk("__key_check: key %p {%08x} should be {%08x}\n", 428c2ecf20Sopenharmony_ci key, key->magic, KEY_DEBUG_MAGIC); 438c2ecf20Sopenharmony_ci BUG(); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Get the key quota record for a user, allocating a new record if one doesn't 498c2ecf20Sopenharmony_ci * already exist. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistruct key_user *key_user_lookup(kuid_t uid) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct key_user *candidate = NULL, *user; 548c2ecf20Sopenharmony_ci struct rb_node *parent, **p; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_citry_again: 578c2ecf20Sopenharmony_ci parent = NULL; 588c2ecf20Sopenharmony_ci p = &key_user_tree.rb_node; 598c2ecf20Sopenharmony_ci spin_lock(&key_user_lock); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* search the tree for a user record with a matching UID */ 628c2ecf20Sopenharmony_ci while (*p) { 638c2ecf20Sopenharmony_ci parent = *p; 648c2ecf20Sopenharmony_ci user = rb_entry(parent, struct key_user, node); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (uid_lt(uid, user->uid)) 678c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 688c2ecf20Sopenharmony_ci else if (uid_gt(uid, user->uid)) 698c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 708c2ecf20Sopenharmony_ci else 718c2ecf20Sopenharmony_ci goto found; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* if we get here, we failed to find a match in the tree */ 758c2ecf20Sopenharmony_ci if (!candidate) { 768c2ecf20Sopenharmony_ci /* allocate a candidate user record if we don't already have 778c2ecf20Sopenharmony_ci * one */ 788c2ecf20Sopenharmony_ci spin_unlock(&key_user_lock); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci user = NULL; 818c2ecf20Sopenharmony_ci candidate = kmalloc(sizeof(struct key_user), GFP_KERNEL); 828c2ecf20Sopenharmony_ci if (unlikely(!candidate)) 838c2ecf20Sopenharmony_ci goto out; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* the allocation may have scheduled, so we need to repeat the 868c2ecf20Sopenharmony_ci * search lest someone else added the record whilst we were 878c2ecf20Sopenharmony_ci * asleep */ 888c2ecf20Sopenharmony_ci goto try_again; 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* if we get here, then the user record still hadn't appeared on the 928c2ecf20Sopenharmony_ci * second pass - so we use the candidate record */ 938c2ecf20Sopenharmony_ci refcount_set(&candidate->usage, 1); 948c2ecf20Sopenharmony_ci atomic_set(&candidate->nkeys, 0); 958c2ecf20Sopenharmony_ci atomic_set(&candidate->nikeys, 0); 968c2ecf20Sopenharmony_ci candidate->uid = uid; 978c2ecf20Sopenharmony_ci candidate->qnkeys = 0; 988c2ecf20Sopenharmony_ci candidate->qnbytes = 0; 998c2ecf20Sopenharmony_ci spin_lock_init(&candidate->lock); 1008c2ecf20Sopenharmony_ci mutex_init(&candidate->cons_lock); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci rb_link_node(&candidate->node, parent, p); 1038c2ecf20Sopenharmony_ci rb_insert_color(&candidate->node, &key_user_tree); 1048c2ecf20Sopenharmony_ci spin_unlock(&key_user_lock); 1058c2ecf20Sopenharmony_ci user = candidate; 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* okay - we found a user record for this UID */ 1098c2ecf20Sopenharmony_cifound: 1108c2ecf20Sopenharmony_ci refcount_inc(&user->usage); 1118c2ecf20Sopenharmony_ci spin_unlock(&key_user_lock); 1128c2ecf20Sopenharmony_ci kfree(candidate); 1138c2ecf20Sopenharmony_ciout: 1148c2ecf20Sopenharmony_ci return user; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* 1188c2ecf20Sopenharmony_ci * Dispose of a user structure 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_civoid key_user_put(struct key_user *user) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci if (refcount_dec_and_lock(&user->usage, &key_user_lock)) { 1238c2ecf20Sopenharmony_ci rb_erase(&user->node, &key_user_tree); 1248c2ecf20Sopenharmony_ci spin_unlock(&key_user_lock); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci kfree(user); 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * Allocate a serial number for a key. These are assigned randomly to avoid 1328c2ecf20Sopenharmony_ci * security issues through covert channel problems. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_cistatic inline void key_alloc_serial(struct key *key) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct rb_node *parent, **p; 1378c2ecf20Sopenharmony_ci struct key *xkey; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* propose a random serial number and look for a hole for it in the 1408c2ecf20Sopenharmony_ci * serial number tree */ 1418c2ecf20Sopenharmony_ci do { 1428c2ecf20Sopenharmony_ci get_random_bytes(&key->serial, sizeof(key->serial)); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci key->serial >>= 1; /* negative numbers are not permitted */ 1458c2ecf20Sopenharmony_ci } while (key->serial < 3); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci spin_lock(&key_serial_lock); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ciattempt_insertion: 1508c2ecf20Sopenharmony_ci parent = NULL; 1518c2ecf20Sopenharmony_ci p = &key_serial_tree.rb_node; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci while (*p) { 1548c2ecf20Sopenharmony_ci parent = *p; 1558c2ecf20Sopenharmony_ci xkey = rb_entry(parent, struct key, serial_node); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (key->serial < xkey->serial) 1588c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 1598c2ecf20Sopenharmony_ci else if (key->serial > xkey->serial) 1608c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci goto serial_exists; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* we've found a suitable hole - arrange for this key to occupy it */ 1668c2ecf20Sopenharmony_ci rb_link_node(&key->serial_node, parent, p); 1678c2ecf20Sopenharmony_ci rb_insert_color(&key->serial_node, &key_serial_tree); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci spin_unlock(&key_serial_lock); 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* we found a key with the proposed serial number - walk the tree from 1738c2ecf20Sopenharmony_ci * that point looking for the next unused serial number */ 1748c2ecf20Sopenharmony_ciserial_exists: 1758c2ecf20Sopenharmony_ci for (;;) { 1768c2ecf20Sopenharmony_ci key->serial++; 1778c2ecf20Sopenharmony_ci if (key->serial < 3) { 1788c2ecf20Sopenharmony_ci key->serial = 3; 1798c2ecf20Sopenharmony_ci goto attempt_insertion; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci parent = rb_next(parent); 1838c2ecf20Sopenharmony_ci if (!parent) 1848c2ecf20Sopenharmony_ci goto attempt_insertion; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci xkey = rb_entry(parent, struct key, serial_node); 1878c2ecf20Sopenharmony_ci if (key->serial < xkey->serial) 1888c2ecf20Sopenharmony_ci goto attempt_insertion; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/** 1938c2ecf20Sopenharmony_ci * key_alloc - Allocate a key of the specified type. 1948c2ecf20Sopenharmony_ci * @type: The type of key to allocate. 1958c2ecf20Sopenharmony_ci * @desc: The key description to allow the key to be searched out. 1968c2ecf20Sopenharmony_ci * @uid: The owner of the new key. 1978c2ecf20Sopenharmony_ci * @gid: The group ID for the new key's group permissions. 1988c2ecf20Sopenharmony_ci * @cred: The credentials specifying UID namespace. 1998c2ecf20Sopenharmony_ci * @perm: The permissions mask of the new key. 2008c2ecf20Sopenharmony_ci * @flags: Flags specifying quota properties. 2018c2ecf20Sopenharmony_ci * @restrict_link: Optional link restriction for new keyrings. 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * Allocate a key of the specified type with the attributes given. The key is 2048c2ecf20Sopenharmony_ci * returned in an uninstantiated state and the caller needs to instantiate the 2058c2ecf20Sopenharmony_ci * key before returning. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * The restrict_link structure (if not NULL) will be freed when the 2088c2ecf20Sopenharmony_ci * keyring is destroyed, so it must be dynamically allocated. 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * The user's key count quota is updated to reflect the creation of the key and 2118c2ecf20Sopenharmony_ci * the user's key data quota has the default for the key type reserved. The 2128c2ecf20Sopenharmony_ci * instantiation function should amend this as necessary. If insufficient 2138c2ecf20Sopenharmony_ci * quota is available, -EDQUOT will be returned. 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * The LSM security modules can prevent a key being created, in which case 2168c2ecf20Sopenharmony_ci * -EACCES will be returned. 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * Returns a pointer to the new key if successful and an error code otherwise. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * Note that the caller needs to ensure the key type isn't uninstantiated. 2218c2ecf20Sopenharmony_ci * Internally this can be done by locking key_types_sem. Externally, this can 2228c2ecf20Sopenharmony_ci * be done by either never unregistering the key type, or making sure 2238c2ecf20Sopenharmony_ci * key_alloc() calls don't race with module unloading. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_cistruct key *key_alloc(struct key_type *type, const char *desc, 2268c2ecf20Sopenharmony_ci kuid_t uid, kgid_t gid, const struct cred *cred, 2278c2ecf20Sopenharmony_ci key_perm_t perm, unsigned long flags, 2288c2ecf20Sopenharmony_ci struct key_restriction *restrict_link) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct key_user *user = NULL; 2318c2ecf20Sopenharmony_ci struct key *key; 2328c2ecf20Sopenharmony_ci size_t desclen, quotalen; 2338c2ecf20Sopenharmony_ci int ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci key = ERR_PTR(-EINVAL); 2368c2ecf20Sopenharmony_ci if (!desc || !*desc) 2378c2ecf20Sopenharmony_ci goto error; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (type->vet_description) { 2408c2ecf20Sopenharmony_ci ret = type->vet_description(desc); 2418c2ecf20Sopenharmony_ci if (ret < 0) { 2428c2ecf20Sopenharmony_ci key = ERR_PTR(ret); 2438c2ecf20Sopenharmony_ci goto error; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci desclen = strlen(desc); 2488c2ecf20Sopenharmony_ci quotalen = desclen + 1 + type->def_datalen; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* get hold of the key tracking for this user */ 2518c2ecf20Sopenharmony_ci user = key_user_lookup(uid); 2528c2ecf20Sopenharmony_ci if (!user) 2538c2ecf20Sopenharmony_ci goto no_memory_1; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* check that the user's quota permits allocation of another key and 2568c2ecf20Sopenharmony_ci * its description */ 2578c2ecf20Sopenharmony_ci if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { 2588c2ecf20Sopenharmony_ci unsigned maxkeys = uid_eq(uid, GLOBAL_ROOT_UID) ? 2598c2ecf20Sopenharmony_ci key_quota_root_maxkeys : key_quota_maxkeys; 2608c2ecf20Sopenharmony_ci unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ? 2618c2ecf20Sopenharmony_ci key_quota_root_maxbytes : key_quota_maxbytes; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci spin_lock(&user->lock); 2648c2ecf20Sopenharmony_ci if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) { 2658c2ecf20Sopenharmony_ci if (user->qnkeys + 1 > maxkeys || 2668c2ecf20Sopenharmony_ci user->qnbytes + quotalen > maxbytes || 2678c2ecf20Sopenharmony_ci user->qnbytes + quotalen < user->qnbytes) 2688c2ecf20Sopenharmony_ci goto no_quota; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci user->qnkeys++; 2728c2ecf20Sopenharmony_ci user->qnbytes += quotalen; 2738c2ecf20Sopenharmony_ci spin_unlock(&user->lock); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* allocate and initialise the key and its description */ 2778c2ecf20Sopenharmony_ci key = kmem_cache_zalloc(key_jar, GFP_KERNEL); 2788c2ecf20Sopenharmony_ci if (!key) 2798c2ecf20Sopenharmony_ci goto no_memory_2; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci key->index_key.desc_len = desclen; 2828c2ecf20Sopenharmony_ci key->index_key.description = kmemdup(desc, desclen + 1, GFP_KERNEL); 2838c2ecf20Sopenharmony_ci if (!key->index_key.description) 2848c2ecf20Sopenharmony_ci goto no_memory_3; 2858c2ecf20Sopenharmony_ci key->index_key.type = type; 2868c2ecf20Sopenharmony_ci key_set_index_key(&key->index_key); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci refcount_set(&key->usage, 1); 2898c2ecf20Sopenharmony_ci init_rwsem(&key->sem); 2908c2ecf20Sopenharmony_ci lockdep_set_class(&key->sem, &type->lock_class); 2918c2ecf20Sopenharmony_ci key->user = user; 2928c2ecf20Sopenharmony_ci key->quotalen = quotalen; 2938c2ecf20Sopenharmony_ci key->datalen = type->def_datalen; 2948c2ecf20Sopenharmony_ci key->uid = uid; 2958c2ecf20Sopenharmony_ci key->gid = gid; 2968c2ecf20Sopenharmony_ci key->perm = perm; 2978c2ecf20Sopenharmony_ci key->expiry = TIME64_MAX; 2988c2ecf20Sopenharmony_ci key->restrict_link = restrict_link; 2998c2ecf20Sopenharmony_ci key->last_used_at = ktime_get_real_seconds(); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) 3028c2ecf20Sopenharmony_ci key->flags |= 1 << KEY_FLAG_IN_QUOTA; 3038c2ecf20Sopenharmony_ci if (flags & KEY_ALLOC_BUILT_IN) 3048c2ecf20Sopenharmony_ci key->flags |= 1 << KEY_FLAG_BUILTIN; 3058c2ecf20Sopenharmony_ci if (flags & KEY_ALLOC_UID_KEYRING) 3068c2ecf20Sopenharmony_ci key->flags |= 1 << KEY_FLAG_UID_KEYRING; 3078c2ecf20Sopenharmony_ci if (flags & KEY_ALLOC_SET_KEEP) 3088c2ecf20Sopenharmony_ci key->flags |= 1 << KEY_FLAG_KEEP; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci#ifdef KEY_DEBUGGING 3118c2ecf20Sopenharmony_ci key->magic = KEY_DEBUG_MAGIC; 3128c2ecf20Sopenharmony_ci#endif 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* let the security module know about the key */ 3158c2ecf20Sopenharmony_ci ret = security_key_alloc(key, cred, flags); 3168c2ecf20Sopenharmony_ci if (ret < 0) 3178c2ecf20Sopenharmony_ci goto security_error; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* publish the key by giving it a serial number */ 3208c2ecf20Sopenharmony_ci refcount_inc(&key->domain_tag->usage); 3218c2ecf20Sopenharmony_ci atomic_inc(&user->nkeys); 3228c2ecf20Sopenharmony_ci key_alloc_serial(key); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cierror: 3258c2ecf20Sopenharmony_ci return key; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cisecurity_error: 3288c2ecf20Sopenharmony_ci kfree(key->description); 3298c2ecf20Sopenharmony_ci kmem_cache_free(key_jar, key); 3308c2ecf20Sopenharmony_ci if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { 3318c2ecf20Sopenharmony_ci spin_lock(&user->lock); 3328c2ecf20Sopenharmony_ci user->qnkeys--; 3338c2ecf20Sopenharmony_ci user->qnbytes -= quotalen; 3348c2ecf20Sopenharmony_ci spin_unlock(&user->lock); 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci key_user_put(user); 3378c2ecf20Sopenharmony_ci key = ERR_PTR(ret); 3388c2ecf20Sopenharmony_ci goto error; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cino_memory_3: 3418c2ecf20Sopenharmony_ci kmem_cache_free(key_jar, key); 3428c2ecf20Sopenharmony_cino_memory_2: 3438c2ecf20Sopenharmony_ci if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) { 3448c2ecf20Sopenharmony_ci spin_lock(&user->lock); 3458c2ecf20Sopenharmony_ci user->qnkeys--; 3468c2ecf20Sopenharmony_ci user->qnbytes -= quotalen; 3478c2ecf20Sopenharmony_ci spin_unlock(&user->lock); 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci key_user_put(user); 3508c2ecf20Sopenharmony_cino_memory_1: 3518c2ecf20Sopenharmony_ci key = ERR_PTR(-ENOMEM); 3528c2ecf20Sopenharmony_ci goto error; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cino_quota: 3558c2ecf20Sopenharmony_ci spin_unlock(&user->lock); 3568c2ecf20Sopenharmony_ci key_user_put(user); 3578c2ecf20Sopenharmony_ci key = ERR_PTR(-EDQUOT); 3588c2ecf20Sopenharmony_ci goto error; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_alloc); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/** 3638c2ecf20Sopenharmony_ci * key_payload_reserve - Adjust data quota reservation for the key's payload 3648c2ecf20Sopenharmony_ci * @key: The key to make the reservation for. 3658c2ecf20Sopenharmony_ci * @datalen: The amount of data payload the caller now wants. 3668c2ecf20Sopenharmony_ci * 3678c2ecf20Sopenharmony_ci * Adjust the amount of the owning user's key data quota that a key reserves. 3688c2ecf20Sopenharmony_ci * If the amount is increased, then -EDQUOT may be returned if there isn't 3698c2ecf20Sopenharmony_ci * enough free quota available. 3708c2ecf20Sopenharmony_ci * 3718c2ecf20Sopenharmony_ci * If successful, 0 is returned. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ciint key_payload_reserve(struct key *key, size_t datalen) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci int delta = (int)datalen - key->datalen; 3768c2ecf20Sopenharmony_ci int ret = 0; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci key_check(key); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* contemplate the quota adjustment */ 3818c2ecf20Sopenharmony_ci if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { 3828c2ecf20Sopenharmony_ci unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ? 3838c2ecf20Sopenharmony_ci key_quota_root_maxbytes : key_quota_maxbytes; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci spin_lock(&key->user->lock); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (delta > 0 && 3888c2ecf20Sopenharmony_ci (key->user->qnbytes + delta > maxbytes || 3898c2ecf20Sopenharmony_ci key->user->qnbytes + delta < key->user->qnbytes)) { 3908c2ecf20Sopenharmony_ci ret = -EDQUOT; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci else { 3938c2ecf20Sopenharmony_ci key->user->qnbytes += delta; 3948c2ecf20Sopenharmony_ci key->quotalen += delta; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci spin_unlock(&key->user->lock); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* change the recorded data length if that didn't generate an error */ 4008c2ecf20Sopenharmony_ci if (ret == 0) 4018c2ecf20Sopenharmony_ci key->datalen = datalen; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return ret; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_payload_reserve); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/* 4088c2ecf20Sopenharmony_ci * Change the key state to being instantiated. 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_cistatic void mark_key_instantiated(struct key *key, int reject_error) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci /* Commit the payload before setting the state; barrier versus 4138c2ecf20Sopenharmony_ci * key_read_state(). 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_ci smp_store_release(&key->state, 4168c2ecf20Sopenharmony_ci (reject_error < 0) ? reject_error : KEY_IS_POSITIVE); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* 4208c2ecf20Sopenharmony_ci * Instantiate a key and link it into the target keyring atomically. Must be 4218c2ecf20Sopenharmony_ci * called with the target keyring's semaphore writelocked. The target key's 4228c2ecf20Sopenharmony_ci * semaphore need not be locked as instantiation is serialised by 4238c2ecf20Sopenharmony_ci * key_construction_mutex. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_cistatic int __key_instantiate_and_link(struct key *key, 4268c2ecf20Sopenharmony_ci struct key_preparsed_payload *prep, 4278c2ecf20Sopenharmony_ci struct key *keyring, 4288c2ecf20Sopenharmony_ci struct key *authkey, 4298c2ecf20Sopenharmony_ci struct assoc_array_edit **_edit) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci int ret, awaken; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci key_check(key); 4348c2ecf20Sopenharmony_ci key_check(keyring); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci awaken = 0; 4378c2ecf20Sopenharmony_ci ret = -EBUSY; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci mutex_lock(&key_construction_mutex); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* can't instantiate twice */ 4428c2ecf20Sopenharmony_ci if (key->state == KEY_IS_UNINSTANTIATED) { 4438c2ecf20Sopenharmony_ci /* instantiate the key */ 4448c2ecf20Sopenharmony_ci ret = key->type->instantiate(key, prep); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (ret == 0) { 4478c2ecf20Sopenharmony_ci /* mark the key as being instantiated */ 4488c2ecf20Sopenharmony_ci atomic_inc(&key->user->nikeys); 4498c2ecf20Sopenharmony_ci mark_key_instantiated(key, 0); 4508c2ecf20Sopenharmony_ci notify_key(key, NOTIFY_KEY_INSTANTIATED, 0); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) 4538c2ecf20Sopenharmony_ci awaken = 1; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* and link it into the destination keyring */ 4568c2ecf20Sopenharmony_ci if (keyring) { 4578c2ecf20Sopenharmony_ci if (test_bit(KEY_FLAG_KEEP, &keyring->flags)) 4588c2ecf20Sopenharmony_ci set_bit(KEY_FLAG_KEEP, &key->flags); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci __key_link(keyring, key, _edit); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* disable the authorisation key */ 4648c2ecf20Sopenharmony_ci if (authkey) 4658c2ecf20Sopenharmony_ci key_invalidate(authkey); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (prep->expiry != TIME64_MAX) 4688c2ecf20Sopenharmony_ci key_set_expiry(key, prep->expiry); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci mutex_unlock(&key_construction_mutex); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* wake up anyone waiting for a key to be constructed */ 4758c2ecf20Sopenharmony_ci if (awaken) 4768c2ecf20Sopenharmony_ci wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return ret; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/** 4828c2ecf20Sopenharmony_ci * key_instantiate_and_link - Instantiate a key and link it into the keyring. 4838c2ecf20Sopenharmony_ci * @key: The key to instantiate. 4848c2ecf20Sopenharmony_ci * @data: The data to use to instantiate the keyring. 4858c2ecf20Sopenharmony_ci * @datalen: The length of @data. 4868c2ecf20Sopenharmony_ci * @keyring: Keyring to create a link in on success (or NULL). 4878c2ecf20Sopenharmony_ci * @authkey: The authorisation token permitting instantiation. 4888c2ecf20Sopenharmony_ci * 4898c2ecf20Sopenharmony_ci * Instantiate a key that's in the uninstantiated state using the provided data 4908c2ecf20Sopenharmony_ci * and, if successful, link it in to the destination keyring if one is 4918c2ecf20Sopenharmony_ci * supplied. 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * If successful, 0 is returned, the authorisation token is revoked and anyone 4948c2ecf20Sopenharmony_ci * waiting for the key is woken up. If the key was already instantiated, 4958c2ecf20Sopenharmony_ci * -EBUSY will be returned. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ciint key_instantiate_and_link(struct key *key, 4988c2ecf20Sopenharmony_ci const void *data, 4998c2ecf20Sopenharmony_ci size_t datalen, 5008c2ecf20Sopenharmony_ci struct key *keyring, 5018c2ecf20Sopenharmony_ci struct key *authkey) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct key_preparsed_payload prep; 5048c2ecf20Sopenharmony_ci struct assoc_array_edit *edit = NULL; 5058c2ecf20Sopenharmony_ci int ret; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci memset(&prep, 0, sizeof(prep)); 5088c2ecf20Sopenharmony_ci prep.data = data; 5098c2ecf20Sopenharmony_ci prep.datalen = datalen; 5108c2ecf20Sopenharmony_ci prep.quotalen = key->type->def_datalen; 5118c2ecf20Sopenharmony_ci prep.expiry = TIME64_MAX; 5128c2ecf20Sopenharmony_ci if (key->type->preparse) { 5138c2ecf20Sopenharmony_ci ret = key->type->preparse(&prep); 5148c2ecf20Sopenharmony_ci if (ret < 0) 5158c2ecf20Sopenharmony_ci goto error; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (keyring) { 5198c2ecf20Sopenharmony_ci ret = __key_link_lock(keyring, &key->index_key); 5208c2ecf20Sopenharmony_ci if (ret < 0) 5218c2ecf20Sopenharmony_ci goto error; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci ret = __key_link_begin(keyring, &key->index_key, &edit); 5248c2ecf20Sopenharmony_ci if (ret < 0) 5258c2ecf20Sopenharmony_ci goto error_link_end; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (keyring->restrict_link && keyring->restrict_link->check) { 5288c2ecf20Sopenharmony_ci struct key_restriction *keyres = keyring->restrict_link; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci ret = keyres->check(keyring, key->type, &prep.payload, 5318c2ecf20Sopenharmony_ci keyres->key); 5328c2ecf20Sopenharmony_ci if (ret < 0) 5338c2ecf20Sopenharmony_ci goto error_link_end; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_cierror_link_end: 5408c2ecf20Sopenharmony_ci if (keyring) 5418c2ecf20Sopenharmony_ci __key_link_end(keyring, &key->index_key, edit); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cierror: 5448c2ecf20Sopenharmony_ci if (key->type->preparse) 5458c2ecf20Sopenharmony_ci key->type->free_preparse(&prep); 5468c2ecf20Sopenharmony_ci return ret; 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_instantiate_and_link); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/** 5528c2ecf20Sopenharmony_ci * key_reject_and_link - Negatively instantiate a key and link it into the keyring. 5538c2ecf20Sopenharmony_ci * @key: The key to instantiate. 5548c2ecf20Sopenharmony_ci * @timeout: The timeout on the negative key. 5558c2ecf20Sopenharmony_ci * @error: The error to return when the key is hit. 5568c2ecf20Sopenharmony_ci * @keyring: Keyring to create a link in on success (or NULL). 5578c2ecf20Sopenharmony_ci * @authkey: The authorisation token permitting instantiation. 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * Negatively instantiate a key that's in the uninstantiated state and, if 5608c2ecf20Sopenharmony_ci * successful, set its timeout and stored error and link it in to the 5618c2ecf20Sopenharmony_ci * destination keyring if one is supplied. The key and any links to the key 5628c2ecf20Sopenharmony_ci * will be automatically garbage collected after the timeout expires. 5638c2ecf20Sopenharmony_ci * 5648c2ecf20Sopenharmony_ci * Negative keys are used to rate limit repeated request_key() calls by causing 5658c2ecf20Sopenharmony_ci * them to return the stored error code (typically ENOKEY) until the negative 5668c2ecf20Sopenharmony_ci * key expires. 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * If successful, 0 is returned, the authorisation token is revoked and anyone 5698c2ecf20Sopenharmony_ci * waiting for the key is woken up. If the key was already instantiated, 5708c2ecf20Sopenharmony_ci * -EBUSY will be returned. 5718c2ecf20Sopenharmony_ci */ 5728c2ecf20Sopenharmony_ciint key_reject_and_link(struct key *key, 5738c2ecf20Sopenharmony_ci unsigned timeout, 5748c2ecf20Sopenharmony_ci unsigned error, 5758c2ecf20Sopenharmony_ci struct key *keyring, 5768c2ecf20Sopenharmony_ci struct key *authkey) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct assoc_array_edit *edit = NULL; 5798c2ecf20Sopenharmony_ci int ret, awaken, link_ret = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci key_check(key); 5828c2ecf20Sopenharmony_ci key_check(keyring); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci awaken = 0; 5858c2ecf20Sopenharmony_ci ret = -EBUSY; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (keyring) { 5888c2ecf20Sopenharmony_ci if (keyring->restrict_link) 5898c2ecf20Sopenharmony_ci return -EPERM; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci link_ret = __key_link_lock(keyring, &key->index_key); 5928c2ecf20Sopenharmony_ci if (link_ret == 0) { 5938c2ecf20Sopenharmony_ci link_ret = __key_link_begin(keyring, &key->index_key, &edit); 5948c2ecf20Sopenharmony_ci if (link_ret < 0) 5958c2ecf20Sopenharmony_ci __key_link_end(keyring, &key->index_key, edit); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci mutex_lock(&key_construction_mutex); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* can't instantiate twice */ 6028c2ecf20Sopenharmony_ci if (key->state == KEY_IS_UNINSTANTIATED) { 6038c2ecf20Sopenharmony_ci /* mark the key as being negatively instantiated */ 6048c2ecf20Sopenharmony_ci atomic_inc(&key->user->nikeys); 6058c2ecf20Sopenharmony_ci mark_key_instantiated(key, -error); 6068c2ecf20Sopenharmony_ci notify_key(key, NOTIFY_KEY_INSTANTIATED, -error); 6078c2ecf20Sopenharmony_ci key_set_expiry(key, ktime_get_real_seconds() + timeout); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) 6108c2ecf20Sopenharmony_ci awaken = 1; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci ret = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* and link it into the destination keyring */ 6158c2ecf20Sopenharmony_ci if (keyring && link_ret == 0) 6168c2ecf20Sopenharmony_ci __key_link(keyring, key, &edit); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* disable the authorisation key */ 6198c2ecf20Sopenharmony_ci if (authkey) 6208c2ecf20Sopenharmony_ci key_invalidate(authkey); 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci mutex_unlock(&key_construction_mutex); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (keyring && link_ret == 0) 6268c2ecf20Sopenharmony_ci __key_link_end(keyring, &key->index_key, edit); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* wake up anyone waiting for a key to be constructed */ 6298c2ecf20Sopenharmony_ci if (awaken) 6308c2ecf20Sopenharmony_ci wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci return ret == 0 ? link_ret : ret; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_reject_and_link); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci/** 6378c2ecf20Sopenharmony_ci * key_put - Discard a reference to a key. 6388c2ecf20Sopenharmony_ci * @key: The key to discard a reference from. 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * Discard a reference to a key, and when all the references are gone, we 6418c2ecf20Sopenharmony_ci * schedule the cleanup task to come and pull it out of the tree in process 6428c2ecf20Sopenharmony_ci * context at some later time. 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_civoid key_put(struct key *key) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci if (key) { 6478c2ecf20Sopenharmony_ci key_check(key); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci if (refcount_dec_and_test(&key->usage)) 6508c2ecf20Sopenharmony_ci schedule_work(&key_gc_work); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_put); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci/* 6568c2ecf20Sopenharmony_ci * Find a key by its serial number. 6578c2ecf20Sopenharmony_ci */ 6588c2ecf20Sopenharmony_cistruct key *key_lookup(key_serial_t id) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci struct rb_node *n; 6618c2ecf20Sopenharmony_ci struct key *key; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci spin_lock(&key_serial_lock); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* search the tree for the specified key */ 6668c2ecf20Sopenharmony_ci n = key_serial_tree.rb_node; 6678c2ecf20Sopenharmony_ci while (n) { 6688c2ecf20Sopenharmony_ci key = rb_entry(n, struct key, serial_node); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (id < key->serial) 6718c2ecf20Sopenharmony_ci n = n->rb_left; 6728c2ecf20Sopenharmony_ci else if (id > key->serial) 6738c2ecf20Sopenharmony_ci n = n->rb_right; 6748c2ecf20Sopenharmony_ci else 6758c2ecf20Sopenharmony_ci goto found; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cinot_found: 6798c2ecf20Sopenharmony_ci key = ERR_PTR(-ENOKEY); 6808c2ecf20Sopenharmony_ci goto error; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cifound: 6838c2ecf20Sopenharmony_ci /* A key is allowed to be looked up only if someone still owns a 6848c2ecf20Sopenharmony_ci * reference to it - otherwise it's awaiting the gc. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci if (!refcount_inc_not_zero(&key->usage)) 6878c2ecf20Sopenharmony_ci goto not_found; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cierror: 6908c2ecf20Sopenharmony_ci spin_unlock(&key_serial_lock); 6918c2ecf20Sopenharmony_ci return key; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* 6958c2ecf20Sopenharmony_ci * Find and lock the specified key type against removal. 6968c2ecf20Sopenharmony_ci * 6978c2ecf20Sopenharmony_ci * We return with the sem read-locked if successful. If the type wasn't 6988c2ecf20Sopenharmony_ci * available -ENOKEY is returned instead. 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_cistruct key_type *key_type_lookup(const char *type) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci struct key_type *ktype; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci down_read(&key_types_sem); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci /* look up the key type to see if it's one of the registered kernel 7078c2ecf20Sopenharmony_ci * types */ 7088c2ecf20Sopenharmony_ci list_for_each_entry(ktype, &key_types_list, link) { 7098c2ecf20Sopenharmony_ci if (strcmp(ktype->name, type) == 0) 7108c2ecf20Sopenharmony_ci goto found_kernel_type; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci up_read(&key_types_sem); 7148c2ecf20Sopenharmony_ci ktype = ERR_PTR(-ENOKEY); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cifound_kernel_type: 7178c2ecf20Sopenharmony_ci return ktype; 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_civoid key_set_timeout(struct key *key, unsigned timeout) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci time64_t expiry = TIME64_MAX; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* make the changes with the locks held to prevent races */ 7258c2ecf20Sopenharmony_ci down_write(&key->sem); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci if (timeout > 0) 7288c2ecf20Sopenharmony_ci expiry = ktime_get_real_seconds() + timeout; 7298c2ecf20Sopenharmony_ci key_set_expiry(key, expiry); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci up_write(&key->sem); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(key_set_timeout); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci/* 7368c2ecf20Sopenharmony_ci * Unlock a key type locked by key_type_lookup(). 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_civoid key_type_put(struct key_type *ktype) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci up_read(&key_types_sem); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/* 7448c2ecf20Sopenharmony_ci * Attempt to update an existing key. 7458c2ecf20Sopenharmony_ci * 7468c2ecf20Sopenharmony_ci * The key is given to us with an incremented refcount that we need to discard 7478c2ecf20Sopenharmony_ci * if we get an error. 7488c2ecf20Sopenharmony_ci */ 7498c2ecf20Sopenharmony_cistatic inline key_ref_t __key_update(key_ref_t key_ref, 7508c2ecf20Sopenharmony_ci struct key_preparsed_payload *prep) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct key *key = key_ref_to_ptr(key_ref); 7538c2ecf20Sopenharmony_ci int ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* need write permission on the key to update it */ 7568c2ecf20Sopenharmony_ci ret = key_permission(key_ref, KEY_NEED_WRITE); 7578c2ecf20Sopenharmony_ci if (ret < 0) 7588c2ecf20Sopenharmony_ci goto error; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci ret = -EEXIST; 7618c2ecf20Sopenharmony_ci if (!key->type->update) 7628c2ecf20Sopenharmony_ci goto error; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci down_write(&key->sem); 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ret = key->type->update(key, prep); 7678c2ecf20Sopenharmony_ci if (ret == 0) { 7688c2ecf20Sopenharmony_ci /* Updating a negative key positively instantiates it */ 7698c2ecf20Sopenharmony_ci mark_key_instantiated(key, 0); 7708c2ecf20Sopenharmony_ci notify_key(key, NOTIFY_KEY_UPDATED, 0); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci up_write(&key->sem); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (ret < 0) 7768c2ecf20Sopenharmony_ci goto error; 7778c2ecf20Sopenharmony_ciout: 7788c2ecf20Sopenharmony_ci return key_ref; 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cierror: 7818c2ecf20Sopenharmony_ci key_put(key); 7828c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 7838c2ecf20Sopenharmony_ci goto out; 7848c2ecf20Sopenharmony_ci} 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci/** 7878c2ecf20Sopenharmony_ci * key_create_or_update - Update or create and instantiate a key. 7888c2ecf20Sopenharmony_ci * @keyring_ref: A pointer to the destination keyring with possession flag. 7898c2ecf20Sopenharmony_ci * @type: The type of key. 7908c2ecf20Sopenharmony_ci * @description: The searchable description for the key. 7918c2ecf20Sopenharmony_ci * @payload: The data to use to instantiate or update the key. 7928c2ecf20Sopenharmony_ci * @plen: The length of @payload. 7938c2ecf20Sopenharmony_ci * @perm: The permissions mask for a new key. 7948c2ecf20Sopenharmony_ci * @flags: The quota flags for a new key. 7958c2ecf20Sopenharmony_ci * 7968c2ecf20Sopenharmony_ci * Search the destination keyring for a key of the same description and if one 7978c2ecf20Sopenharmony_ci * is found, update it, otherwise create and instantiate a new one and create a 7988c2ecf20Sopenharmony_ci * link to it from that keyring. 7998c2ecf20Sopenharmony_ci * 8008c2ecf20Sopenharmony_ci * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be 8018c2ecf20Sopenharmony_ci * concocted. 8028c2ecf20Sopenharmony_ci * 8038c2ecf20Sopenharmony_ci * Returns a pointer to the new key if successful, -ENODEV if the key type 8048c2ecf20Sopenharmony_ci * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the 8058c2ecf20Sopenharmony_ci * caller isn't permitted to modify the keyring or the LSM did not permit 8068c2ecf20Sopenharmony_ci * creation of the key. 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci * On success, the possession flag from the keyring ref will be tacked on to 8098c2ecf20Sopenharmony_ci * the key ref before it is returned. 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_cikey_ref_t key_create_or_update(key_ref_t keyring_ref, 8128c2ecf20Sopenharmony_ci const char *type, 8138c2ecf20Sopenharmony_ci const char *description, 8148c2ecf20Sopenharmony_ci const void *payload, 8158c2ecf20Sopenharmony_ci size_t plen, 8168c2ecf20Sopenharmony_ci key_perm_t perm, 8178c2ecf20Sopenharmony_ci unsigned long flags) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct keyring_index_key index_key = { 8208c2ecf20Sopenharmony_ci .description = description, 8218c2ecf20Sopenharmony_ci }; 8228c2ecf20Sopenharmony_ci struct key_preparsed_payload prep; 8238c2ecf20Sopenharmony_ci struct assoc_array_edit *edit = NULL; 8248c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 8258c2ecf20Sopenharmony_ci struct key *keyring, *key = NULL; 8268c2ecf20Sopenharmony_ci key_ref_t key_ref; 8278c2ecf20Sopenharmony_ci int ret; 8288c2ecf20Sopenharmony_ci struct key_restriction *restrict_link = NULL; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* look up the key type to see if it's one of the registered kernel 8318c2ecf20Sopenharmony_ci * types */ 8328c2ecf20Sopenharmony_ci index_key.type = key_type_lookup(type); 8338c2ecf20Sopenharmony_ci if (IS_ERR(index_key.type)) { 8348c2ecf20Sopenharmony_ci key_ref = ERR_PTR(-ENODEV); 8358c2ecf20Sopenharmony_ci goto error; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci key_ref = ERR_PTR(-EINVAL); 8398c2ecf20Sopenharmony_ci if (!index_key.type->instantiate || 8408c2ecf20Sopenharmony_ci (!index_key.description && !index_key.type->preparse)) 8418c2ecf20Sopenharmony_ci goto error_put_type; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci keyring = key_ref_to_ptr(keyring_ref); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci key_check(keyring); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION)) 8488c2ecf20Sopenharmony_ci restrict_link = keyring->restrict_link; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci key_ref = ERR_PTR(-ENOTDIR); 8518c2ecf20Sopenharmony_ci if (keyring->type != &key_type_keyring) 8528c2ecf20Sopenharmony_ci goto error_put_type; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci memset(&prep, 0, sizeof(prep)); 8558c2ecf20Sopenharmony_ci prep.data = payload; 8568c2ecf20Sopenharmony_ci prep.datalen = plen; 8578c2ecf20Sopenharmony_ci prep.quotalen = index_key.type->def_datalen; 8588c2ecf20Sopenharmony_ci prep.expiry = TIME64_MAX; 8598c2ecf20Sopenharmony_ci if (index_key.type->preparse) { 8608c2ecf20Sopenharmony_ci ret = index_key.type->preparse(&prep); 8618c2ecf20Sopenharmony_ci if (ret < 0) { 8628c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 8638c2ecf20Sopenharmony_ci goto error_free_prep; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci if (!index_key.description) 8668c2ecf20Sopenharmony_ci index_key.description = prep.description; 8678c2ecf20Sopenharmony_ci key_ref = ERR_PTR(-EINVAL); 8688c2ecf20Sopenharmony_ci if (!index_key.description) 8698c2ecf20Sopenharmony_ci goto error_free_prep; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci index_key.desc_len = strlen(index_key.description); 8728c2ecf20Sopenharmony_ci key_set_index_key(&index_key); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci ret = __key_link_lock(keyring, &index_key); 8758c2ecf20Sopenharmony_ci if (ret < 0) { 8768c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 8778c2ecf20Sopenharmony_ci goto error_free_prep; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci ret = __key_link_begin(keyring, &index_key, &edit); 8818c2ecf20Sopenharmony_ci if (ret < 0) { 8828c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 8838c2ecf20Sopenharmony_ci goto error_link_end; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (restrict_link && restrict_link->check) { 8878c2ecf20Sopenharmony_ci ret = restrict_link->check(keyring, index_key.type, 8888c2ecf20Sopenharmony_ci &prep.payload, restrict_link->key); 8898c2ecf20Sopenharmony_ci if (ret < 0) { 8908c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 8918c2ecf20Sopenharmony_ci goto error_link_end; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* if we're going to allocate a new key, we're going to have 8968c2ecf20Sopenharmony_ci * to modify the keyring */ 8978c2ecf20Sopenharmony_ci ret = key_permission(keyring_ref, KEY_NEED_WRITE); 8988c2ecf20Sopenharmony_ci if (ret < 0) { 8998c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 9008c2ecf20Sopenharmony_ci goto error_link_end; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* if it's possible to update this type of key, search for an existing 9048c2ecf20Sopenharmony_ci * key of the same type and description in the destination keyring and 9058c2ecf20Sopenharmony_ci * update that instead if possible 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_ci if (index_key.type->update) { 9088c2ecf20Sopenharmony_ci key_ref = find_key_to_update(keyring_ref, &index_key); 9098c2ecf20Sopenharmony_ci if (key_ref) 9108c2ecf20Sopenharmony_ci goto found_matching_key; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* if the client doesn't provide, decide on the permissions we want */ 9148c2ecf20Sopenharmony_ci if (perm == KEY_PERM_UNDEF) { 9158c2ecf20Sopenharmony_ci perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; 9168c2ecf20Sopenharmony_ci perm |= KEY_USR_VIEW; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (index_key.type->read) 9198c2ecf20Sopenharmony_ci perm |= KEY_POS_READ; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (index_key.type == &key_type_keyring || 9228c2ecf20Sopenharmony_ci index_key.type->update) 9238c2ecf20Sopenharmony_ci perm |= KEY_POS_WRITE; 9248c2ecf20Sopenharmony_ci } 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci /* allocate a new key */ 9278c2ecf20Sopenharmony_ci key = key_alloc(index_key.type, index_key.description, 9288c2ecf20Sopenharmony_ci cred->fsuid, cred->fsgid, cred, perm, flags, NULL); 9298c2ecf20Sopenharmony_ci if (IS_ERR(key)) { 9308c2ecf20Sopenharmony_ci key_ref = ERR_CAST(key); 9318c2ecf20Sopenharmony_ci goto error_link_end; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* instantiate it and link it into the target keyring */ 9358c2ecf20Sopenharmony_ci ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &edit); 9368c2ecf20Sopenharmony_ci if (ret < 0) { 9378c2ecf20Sopenharmony_ci key_put(key); 9388c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 9398c2ecf20Sopenharmony_ci goto error_link_end; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci ima_post_key_create_or_update(keyring, key, payload, plen, 9438c2ecf20Sopenharmony_ci flags, true); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cierror_link_end: 9488c2ecf20Sopenharmony_ci __key_link_end(keyring, &index_key, edit); 9498c2ecf20Sopenharmony_cierror_free_prep: 9508c2ecf20Sopenharmony_ci if (index_key.type->preparse) 9518c2ecf20Sopenharmony_ci index_key.type->free_preparse(&prep); 9528c2ecf20Sopenharmony_cierror_put_type: 9538c2ecf20Sopenharmony_ci key_type_put(index_key.type); 9548c2ecf20Sopenharmony_cierror: 9558c2ecf20Sopenharmony_ci return key_ref; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci found_matching_key: 9588c2ecf20Sopenharmony_ci /* we found a matching key, so we're going to try to update it 9598c2ecf20Sopenharmony_ci * - we can drop the locks first as we have the key pinned 9608c2ecf20Sopenharmony_ci */ 9618c2ecf20Sopenharmony_ci __key_link_end(keyring, &index_key, edit); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci key = key_ref_to_ptr(key_ref); 9648c2ecf20Sopenharmony_ci if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { 9658c2ecf20Sopenharmony_ci ret = wait_for_key_construction(key, true); 9668c2ecf20Sopenharmony_ci if (ret < 0) { 9678c2ecf20Sopenharmony_ci key_ref_put(key_ref); 9688c2ecf20Sopenharmony_ci key_ref = ERR_PTR(ret); 9698c2ecf20Sopenharmony_ci goto error_free_prep; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci key_ref = __key_update(key_ref, &prep); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (!IS_ERR(key_ref)) 9768c2ecf20Sopenharmony_ci ima_post_key_create_or_update(keyring, key, 9778c2ecf20Sopenharmony_ci payload, plen, 9788c2ecf20Sopenharmony_ci flags, false); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci goto error_free_prep; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_create_or_update); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci/** 9858c2ecf20Sopenharmony_ci * key_update - Update a key's contents. 9868c2ecf20Sopenharmony_ci * @key_ref: The pointer (plus possession flag) to the key. 9878c2ecf20Sopenharmony_ci * @payload: The data to be used to update the key. 9888c2ecf20Sopenharmony_ci * @plen: The length of @payload. 9898c2ecf20Sopenharmony_ci * 9908c2ecf20Sopenharmony_ci * Attempt to update the contents of a key with the given payload data. The 9918c2ecf20Sopenharmony_ci * caller must be granted Write permission on the key. Negative keys can be 9928c2ecf20Sopenharmony_ci * instantiated by this method. 9938c2ecf20Sopenharmony_ci * 9948c2ecf20Sopenharmony_ci * Returns 0 on success, -EACCES if not permitted and -EOPNOTSUPP if the key 9958c2ecf20Sopenharmony_ci * type does not support updating. The key type may return other errors. 9968c2ecf20Sopenharmony_ci */ 9978c2ecf20Sopenharmony_ciint key_update(key_ref_t key_ref, const void *payload, size_t plen) 9988c2ecf20Sopenharmony_ci{ 9998c2ecf20Sopenharmony_ci struct key_preparsed_payload prep; 10008c2ecf20Sopenharmony_ci struct key *key = key_ref_to_ptr(key_ref); 10018c2ecf20Sopenharmony_ci int ret; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci key_check(key); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci /* the key must be writable */ 10068c2ecf20Sopenharmony_ci ret = key_permission(key_ref, KEY_NEED_WRITE); 10078c2ecf20Sopenharmony_ci if (ret < 0) 10088c2ecf20Sopenharmony_ci return ret; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* attempt to update it if supported */ 10118c2ecf20Sopenharmony_ci if (!key->type->update) 10128c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci memset(&prep, 0, sizeof(prep)); 10158c2ecf20Sopenharmony_ci prep.data = payload; 10168c2ecf20Sopenharmony_ci prep.datalen = plen; 10178c2ecf20Sopenharmony_ci prep.quotalen = key->type->def_datalen; 10188c2ecf20Sopenharmony_ci prep.expiry = TIME64_MAX; 10198c2ecf20Sopenharmony_ci if (key->type->preparse) { 10208c2ecf20Sopenharmony_ci ret = key->type->preparse(&prep); 10218c2ecf20Sopenharmony_ci if (ret < 0) 10228c2ecf20Sopenharmony_ci goto error; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci down_write(&key->sem); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci ret = key->type->update(key, &prep); 10288c2ecf20Sopenharmony_ci if (ret == 0) { 10298c2ecf20Sopenharmony_ci /* Updating a negative key positively instantiates it */ 10308c2ecf20Sopenharmony_ci mark_key_instantiated(key, 0); 10318c2ecf20Sopenharmony_ci notify_key(key, NOTIFY_KEY_UPDATED, 0); 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci up_write(&key->sem); 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_cierror: 10378c2ecf20Sopenharmony_ci if (key->type->preparse) 10388c2ecf20Sopenharmony_ci key->type->free_preparse(&prep); 10398c2ecf20Sopenharmony_ci return ret; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_update); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci/** 10448c2ecf20Sopenharmony_ci * key_revoke - Revoke a key. 10458c2ecf20Sopenharmony_ci * @key: The key to be revoked. 10468c2ecf20Sopenharmony_ci * 10478c2ecf20Sopenharmony_ci * Mark a key as being revoked and ask the type to free up its resources. The 10488c2ecf20Sopenharmony_ci * revocation timeout is set and the key and all its links will be 10498c2ecf20Sopenharmony_ci * automatically garbage collected after key_gc_delay amount of time if they 10508c2ecf20Sopenharmony_ci * are not manually dealt with first. 10518c2ecf20Sopenharmony_ci */ 10528c2ecf20Sopenharmony_civoid key_revoke(struct key *key) 10538c2ecf20Sopenharmony_ci{ 10548c2ecf20Sopenharmony_ci time64_t time; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci key_check(key); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* make sure no one's trying to change or use the key when we mark it 10598c2ecf20Sopenharmony_ci * - we tell lockdep that we might nest because we might be revoking an 10608c2ecf20Sopenharmony_ci * authorisation key whilst holding the sem on a key we've just 10618c2ecf20Sopenharmony_ci * instantiated 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci down_write_nested(&key->sem, 1); 10648c2ecf20Sopenharmony_ci if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags)) { 10658c2ecf20Sopenharmony_ci notify_key(key, NOTIFY_KEY_REVOKED, 0); 10668c2ecf20Sopenharmony_ci if (key->type->revoke) 10678c2ecf20Sopenharmony_ci key->type->revoke(key); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci /* set the death time to no more than the expiry time */ 10708c2ecf20Sopenharmony_ci time = ktime_get_real_seconds(); 10718c2ecf20Sopenharmony_ci if (key->revoked_at == 0 || key->revoked_at > time) { 10728c2ecf20Sopenharmony_ci key->revoked_at = time; 10738c2ecf20Sopenharmony_ci key_schedule_gc(key->revoked_at + key_gc_delay); 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci up_write(&key->sem); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_revoke); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci/** 10828c2ecf20Sopenharmony_ci * key_invalidate - Invalidate a key. 10838c2ecf20Sopenharmony_ci * @key: The key to be invalidated. 10848c2ecf20Sopenharmony_ci * 10858c2ecf20Sopenharmony_ci * Mark a key as being invalidated and have it cleaned up immediately. The key 10868c2ecf20Sopenharmony_ci * is ignored by all searches and other operations from this point. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_civoid key_invalidate(struct key *key) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci kenter("%d", key_serial(key)); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci key_check(key); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { 10958c2ecf20Sopenharmony_ci down_write_nested(&key->sem, 1); 10968c2ecf20Sopenharmony_ci if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) { 10978c2ecf20Sopenharmony_ci notify_key(key, NOTIFY_KEY_INVALIDATED, 0); 10988c2ecf20Sopenharmony_ci key_schedule_gc_links(); 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci up_write(&key->sem); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_invalidate); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/** 11068c2ecf20Sopenharmony_ci * generic_key_instantiate - Simple instantiation of a key from preparsed data 11078c2ecf20Sopenharmony_ci * @key: The key to be instantiated 11088c2ecf20Sopenharmony_ci * @prep: The preparsed data to load. 11098c2ecf20Sopenharmony_ci * 11108c2ecf20Sopenharmony_ci * Instantiate a key from preparsed data. We assume we can just copy the data 11118c2ecf20Sopenharmony_ci * in directly and clear the old pointers. 11128c2ecf20Sopenharmony_ci * 11138c2ecf20Sopenharmony_ci * This can be pointed to directly by the key type instantiate op pointer. 11148c2ecf20Sopenharmony_ci */ 11158c2ecf20Sopenharmony_ciint generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci int ret; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci pr_devel("==>%s()\n", __func__); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci ret = key_payload_reserve(key, prep->quotalen); 11228c2ecf20Sopenharmony_ci if (ret == 0) { 11238c2ecf20Sopenharmony_ci rcu_assign_keypointer(key, prep->payload.data[0]); 11248c2ecf20Sopenharmony_ci key->payload.data[1] = prep->payload.data[1]; 11258c2ecf20Sopenharmony_ci key->payload.data[2] = prep->payload.data[2]; 11268c2ecf20Sopenharmony_ci key->payload.data[3] = prep->payload.data[3]; 11278c2ecf20Sopenharmony_ci prep->payload.data[0] = NULL; 11288c2ecf20Sopenharmony_ci prep->payload.data[1] = NULL; 11298c2ecf20Sopenharmony_ci prep->payload.data[2] = NULL; 11308c2ecf20Sopenharmony_ci prep->payload.data[3] = NULL; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 11338c2ecf20Sopenharmony_ci return ret; 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(generic_key_instantiate); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci/** 11388c2ecf20Sopenharmony_ci * register_key_type - Register a type of key. 11398c2ecf20Sopenharmony_ci * @ktype: The new key type. 11408c2ecf20Sopenharmony_ci * 11418c2ecf20Sopenharmony_ci * Register a new key type. 11428c2ecf20Sopenharmony_ci * 11438c2ecf20Sopenharmony_ci * Returns 0 on success or -EEXIST if a type of this name already exists. 11448c2ecf20Sopenharmony_ci */ 11458c2ecf20Sopenharmony_ciint register_key_type(struct key_type *ktype) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci struct key_type *p; 11488c2ecf20Sopenharmony_ci int ret; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci memset(&ktype->lock_class, 0, sizeof(ktype->lock_class)); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci ret = -EEXIST; 11538c2ecf20Sopenharmony_ci down_write(&key_types_sem); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* disallow key types with the same name */ 11568c2ecf20Sopenharmony_ci list_for_each_entry(p, &key_types_list, link) { 11578c2ecf20Sopenharmony_ci if (strcmp(p->name, ktype->name) == 0) 11588c2ecf20Sopenharmony_ci goto out; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci /* store the type */ 11628c2ecf20Sopenharmony_ci list_add(&ktype->link, &key_types_list); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci pr_notice("Key type %s registered\n", ktype->name); 11658c2ecf20Sopenharmony_ci ret = 0; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ciout: 11688c2ecf20Sopenharmony_ci up_write(&key_types_sem); 11698c2ecf20Sopenharmony_ci return ret; 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(register_key_type); 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci/** 11748c2ecf20Sopenharmony_ci * unregister_key_type - Unregister a type of key. 11758c2ecf20Sopenharmony_ci * @ktype: The key type. 11768c2ecf20Sopenharmony_ci * 11778c2ecf20Sopenharmony_ci * Unregister a key type and mark all the extant keys of this type as dead. 11788c2ecf20Sopenharmony_ci * Those keys of this type are then destroyed to get rid of their payloads and 11798c2ecf20Sopenharmony_ci * they and their links will be garbage collected as soon as possible. 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_civoid unregister_key_type(struct key_type *ktype) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci down_write(&key_types_sem); 11848c2ecf20Sopenharmony_ci list_del_init(&ktype->link); 11858c2ecf20Sopenharmony_ci downgrade_write(&key_types_sem); 11868c2ecf20Sopenharmony_ci key_gc_keytype(ktype); 11878c2ecf20Sopenharmony_ci pr_notice("Key type %s unregistered\n", ktype->name); 11888c2ecf20Sopenharmony_ci up_read(&key_types_sem); 11898c2ecf20Sopenharmony_ci} 11908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(unregister_key_type); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci/* 11938c2ecf20Sopenharmony_ci * Initialise the key management state. 11948c2ecf20Sopenharmony_ci */ 11958c2ecf20Sopenharmony_civoid __init key_init(void) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci /* allocate a slab in which we can store keys */ 11988c2ecf20Sopenharmony_ci key_jar = kmem_cache_create("key_jar", sizeof(struct key), 11998c2ecf20Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* add the special key types */ 12028c2ecf20Sopenharmony_ci list_add_tail(&key_type_keyring.link, &key_types_list); 12038c2ecf20Sopenharmony_ci list_add_tail(&key_type_dead.link, &key_types_list); 12048c2ecf20Sopenharmony_ci list_add_tail(&key_type_user.link, &key_types_list); 12058c2ecf20Sopenharmony_ci list_add_tail(&key_type_logon.link, &key_types_list); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci /* record the root user tracking */ 12088c2ecf20Sopenharmony_ci rb_link_node(&root_key_user.node, 12098c2ecf20Sopenharmony_ci NULL, 12108c2ecf20Sopenharmony_ci &key_user_tree.rb_node); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci rb_insert_color(&root_key_user.node, 12138c2ecf20Sopenharmony_ci &key_user_tree); 12148c2ecf20Sopenharmony_ci} 1215