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