18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* Keyring handling
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2004-2005, 2008, 2013 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/sched.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/security.h>
138c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
148c2ecf20Sopenharmony_ci#include <linux/err.h>
158c2ecf20Sopenharmony_ci#include <linux/user_namespace.h>
168c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
178c2ecf20Sopenharmony_ci#include <keys/keyring-type.h>
188c2ecf20Sopenharmony_ci#include <keys/user-type.h>
198c2ecf20Sopenharmony_ci#include <linux/assoc_array_priv.h>
208c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
218c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
228c2ecf20Sopenharmony_ci#include "internal.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * When plumbing the depths of the key tree, this sets a hard limit
268c2ecf20Sopenharmony_ci * set on how deep we're willing to go.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_ci#define KEYRING_SEARCH_MAX_DEPTH 6
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/*
318c2ecf20Sopenharmony_ci * We mark pointers we pass to the associative array with bit 1 set if
328c2ecf20Sopenharmony_ci * they're keyrings and clear otherwise.
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci#define KEYRING_PTR_SUBTYPE	0x2UL
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic inline bool keyring_ptr_is_keyring(const struct assoc_array_ptr *x)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return (unsigned long)x & KEYRING_PTR_SUBTYPE;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_cistatic inline struct key *keyring_ptr_to_key(const struct assoc_array_ptr *x)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	void *object = assoc_array_ptr_to_leaf(x);
438c2ecf20Sopenharmony_ci	return (struct key *)((unsigned long)object & ~KEYRING_PTR_SUBTYPE);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_cistatic inline void *keyring_key_to_ptr(struct key *key)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	if (key->type == &key_type_keyring)
488c2ecf20Sopenharmony_ci		return (void *)((unsigned long)key | KEYRING_PTR_SUBTYPE);
498c2ecf20Sopenharmony_ci	return key;
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(keyring_name_lock);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/*
558c2ecf20Sopenharmony_ci * Clean up the bits of user_namespace that belong to us.
568c2ecf20Sopenharmony_ci */
578c2ecf20Sopenharmony_civoid key_free_user_ns(struct user_namespace *ns)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	write_lock(&keyring_name_lock);
608c2ecf20Sopenharmony_ci	list_del_init(&ns->keyring_name_list);
618c2ecf20Sopenharmony_ci	write_unlock(&keyring_name_lock);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	key_put(ns->user_keyring_register);
648c2ecf20Sopenharmony_ci#ifdef CONFIG_PERSISTENT_KEYRINGS
658c2ecf20Sopenharmony_ci	key_put(ns->persistent_keyring_register);
668c2ecf20Sopenharmony_ci#endif
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci/*
708c2ecf20Sopenharmony_ci * The keyring key type definition.  Keyrings are simply keys of this type and
718c2ecf20Sopenharmony_ci * can be treated as ordinary keys in addition to having their own special
728c2ecf20Sopenharmony_ci * operations.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistatic int keyring_preparse(struct key_preparsed_payload *prep);
758c2ecf20Sopenharmony_cistatic void keyring_free_preparse(struct key_preparsed_payload *prep);
768c2ecf20Sopenharmony_cistatic int keyring_instantiate(struct key *keyring,
778c2ecf20Sopenharmony_ci			       struct key_preparsed_payload *prep);
788c2ecf20Sopenharmony_cistatic void keyring_revoke(struct key *keyring);
798c2ecf20Sopenharmony_cistatic void keyring_destroy(struct key *keyring);
808c2ecf20Sopenharmony_cistatic void keyring_describe(const struct key *keyring, struct seq_file *m);
818c2ecf20Sopenharmony_cistatic long keyring_read(const struct key *keyring,
828c2ecf20Sopenharmony_ci			 char __user *buffer, size_t buflen);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistruct key_type key_type_keyring = {
858c2ecf20Sopenharmony_ci	.name		= "keyring",
868c2ecf20Sopenharmony_ci	.def_datalen	= 0,
878c2ecf20Sopenharmony_ci	.preparse	= keyring_preparse,
888c2ecf20Sopenharmony_ci	.free_preparse	= keyring_free_preparse,
898c2ecf20Sopenharmony_ci	.instantiate	= keyring_instantiate,
908c2ecf20Sopenharmony_ci	.revoke		= keyring_revoke,
918c2ecf20Sopenharmony_ci	.destroy	= keyring_destroy,
928c2ecf20Sopenharmony_ci	.describe	= keyring_describe,
938c2ecf20Sopenharmony_ci	.read		= keyring_read,
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_type_keyring);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/*
988c2ecf20Sopenharmony_ci * Semaphore to serialise link/link calls to prevent two link calls in parallel
998c2ecf20Sopenharmony_ci * introducing a cycle.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(keyring_serialise_link_lock);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci/*
1048c2ecf20Sopenharmony_ci * Publish the name of a keyring so that it can be found by name (if it has
1058c2ecf20Sopenharmony_ci * one and it doesn't begin with a dot).
1068c2ecf20Sopenharmony_ci */
1078c2ecf20Sopenharmony_cistatic void keyring_publish_name(struct key *keyring)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	struct user_namespace *ns = current_user_ns();
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	if (keyring->description &&
1128c2ecf20Sopenharmony_ci	    keyring->description[0] &&
1138c2ecf20Sopenharmony_ci	    keyring->description[0] != '.') {
1148c2ecf20Sopenharmony_ci		write_lock(&keyring_name_lock);
1158c2ecf20Sopenharmony_ci		list_add_tail(&keyring->name_link, &ns->keyring_name_list);
1168c2ecf20Sopenharmony_ci		write_unlock(&keyring_name_lock);
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * Preparse a keyring payload
1228c2ecf20Sopenharmony_ci */
1238c2ecf20Sopenharmony_cistatic int keyring_preparse(struct key_preparsed_payload *prep)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	return prep->datalen != 0 ? -EINVAL : 0;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/*
1298c2ecf20Sopenharmony_ci * Free a preparse of a user defined key payload
1308c2ecf20Sopenharmony_ci */
1318c2ecf20Sopenharmony_cistatic void keyring_free_preparse(struct key_preparsed_payload *prep)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci/*
1368c2ecf20Sopenharmony_ci * Initialise a keyring.
1378c2ecf20Sopenharmony_ci *
1388c2ecf20Sopenharmony_ci * Returns 0 on success, -EINVAL if given any data.
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_cistatic int keyring_instantiate(struct key *keyring,
1418c2ecf20Sopenharmony_ci			       struct key_preparsed_payload *prep)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	assoc_array_init(&keyring->keys);
1448c2ecf20Sopenharmony_ci	/* make the keyring available by name if it has one */
1458c2ecf20Sopenharmony_ci	keyring_publish_name(keyring);
1468c2ecf20Sopenharmony_ci	return 0;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/*
1508c2ecf20Sopenharmony_ci * Multiply 64-bits by 32-bits to 96-bits and fold back to 64-bit.  Ideally we'd
1518c2ecf20Sopenharmony_ci * fold the carry back too, but that requires inline asm.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_cistatic u64 mult_64x32_and_fold(u64 x, u32 y)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	u64 hi = (u64)(u32)(x >> 32) * y;
1568c2ecf20Sopenharmony_ci	u64 lo = (u64)(u32)(x) * y;
1578c2ecf20Sopenharmony_ci	return lo + ((u64)(u32)hi << 32) + (u32)(hi >> 32);
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/*
1618c2ecf20Sopenharmony_ci * Hash a key type and description.
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_cistatic void hash_key_type_and_desc(struct keyring_index_key *index_key)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	const unsigned level_shift = ASSOC_ARRAY_LEVEL_STEP;
1668c2ecf20Sopenharmony_ci	const unsigned long fan_mask = ASSOC_ARRAY_FAN_MASK;
1678c2ecf20Sopenharmony_ci	const char *description = index_key->description;
1688c2ecf20Sopenharmony_ci	unsigned long hash, type;
1698c2ecf20Sopenharmony_ci	u32 piece;
1708c2ecf20Sopenharmony_ci	u64 acc;
1718c2ecf20Sopenharmony_ci	int n, desc_len = index_key->desc_len;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	type = (unsigned long)index_key->type;
1748c2ecf20Sopenharmony_ci	acc = mult_64x32_and_fold(type, desc_len + 13);
1758c2ecf20Sopenharmony_ci	acc = mult_64x32_and_fold(acc, 9207);
1768c2ecf20Sopenharmony_ci	piece = (unsigned long)index_key->domain_tag;
1778c2ecf20Sopenharmony_ci	acc = mult_64x32_and_fold(acc, piece);
1788c2ecf20Sopenharmony_ci	acc = mult_64x32_and_fold(acc, 9207);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	for (;;) {
1818c2ecf20Sopenharmony_ci		n = desc_len;
1828c2ecf20Sopenharmony_ci		if (n <= 0)
1838c2ecf20Sopenharmony_ci			break;
1848c2ecf20Sopenharmony_ci		if (n > 4)
1858c2ecf20Sopenharmony_ci			n = 4;
1868c2ecf20Sopenharmony_ci		piece = 0;
1878c2ecf20Sopenharmony_ci		memcpy(&piece, description, n);
1888c2ecf20Sopenharmony_ci		description += n;
1898c2ecf20Sopenharmony_ci		desc_len -= n;
1908c2ecf20Sopenharmony_ci		acc = mult_64x32_and_fold(acc, piece);
1918c2ecf20Sopenharmony_ci		acc = mult_64x32_and_fold(acc, 9207);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* Fold the hash down to 32 bits if need be. */
1958c2ecf20Sopenharmony_ci	hash = acc;
1968c2ecf20Sopenharmony_ci	if (ASSOC_ARRAY_KEY_CHUNK_SIZE == 32)
1978c2ecf20Sopenharmony_ci		hash ^= acc >> 32;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	/* Squidge all the keyrings into a separate part of the tree to
2008c2ecf20Sopenharmony_ci	 * ordinary keys by making sure the lowest level segment in the hash is
2018c2ecf20Sopenharmony_ci	 * zero for keyrings and non-zero otherwise.
2028c2ecf20Sopenharmony_ci	 */
2038c2ecf20Sopenharmony_ci	if (index_key->type != &key_type_keyring && (hash & fan_mask) == 0)
2048c2ecf20Sopenharmony_ci		hash |= (hash >> (ASSOC_ARRAY_KEY_CHUNK_SIZE - level_shift)) | 1;
2058c2ecf20Sopenharmony_ci	else if (index_key->type == &key_type_keyring && (hash & fan_mask) != 0)
2068c2ecf20Sopenharmony_ci		hash = (hash + (hash << level_shift)) & ~fan_mask;
2078c2ecf20Sopenharmony_ci	index_key->hash = hash;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci/*
2118c2ecf20Sopenharmony_ci * Finalise an index key to include a part of the description actually in the
2128c2ecf20Sopenharmony_ci * index key, to set the domain tag and to calculate the hash.
2138c2ecf20Sopenharmony_ci */
2148c2ecf20Sopenharmony_civoid key_set_index_key(struct keyring_index_key *index_key)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	static struct key_tag default_domain_tag = { .usage = REFCOUNT_INIT(1), };
2178c2ecf20Sopenharmony_ci	size_t n = min_t(size_t, index_key->desc_len, sizeof(index_key->desc));
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	memcpy(index_key->desc, index_key->description, n);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (!index_key->domain_tag) {
2228c2ecf20Sopenharmony_ci		if (index_key->type->flags & KEY_TYPE_NET_DOMAIN)
2238c2ecf20Sopenharmony_ci			index_key->domain_tag = current->nsproxy->net_ns->key_domain;
2248c2ecf20Sopenharmony_ci		else
2258c2ecf20Sopenharmony_ci			index_key->domain_tag = &default_domain_tag;
2268c2ecf20Sopenharmony_ci	}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	hash_key_type_and_desc(index_key);
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/**
2328c2ecf20Sopenharmony_ci * key_put_tag - Release a ref on a tag.
2338c2ecf20Sopenharmony_ci * @tag: The tag to release.
2348c2ecf20Sopenharmony_ci *
2358c2ecf20Sopenharmony_ci * This releases a reference the given tag and returns true if that ref was the
2368c2ecf20Sopenharmony_ci * last one.
2378c2ecf20Sopenharmony_ci */
2388c2ecf20Sopenharmony_cibool key_put_tag(struct key_tag *tag)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&tag->usage)) {
2418c2ecf20Sopenharmony_ci		kfree_rcu(tag, rcu);
2428c2ecf20Sopenharmony_ci		return true;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return false;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/**
2498c2ecf20Sopenharmony_ci * key_remove_domain - Kill off a key domain and gc its keys
2508c2ecf20Sopenharmony_ci * @domain_tag: The domain tag to release.
2518c2ecf20Sopenharmony_ci *
2528c2ecf20Sopenharmony_ci * This marks a domain tag as being dead and releases a ref on it.  If that
2538c2ecf20Sopenharmony_ci * wasn't the last reference, the garbage collector is poked to try and delete
2548c2ecf20Sopenharmony_ci * all keys that were in the domain.
2558c2ecf20Sopenharmony_ci */
2568c2ecf20Sopenharmony_civoid key_remove_domain(struct key_tag *domain_tag)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	domain_tag->removed = true;
2598c2ecf20Sopenharmony_ci	if (!key_put_tag(domain_tag))
2608c2ecf20Sopenharmony_ci		key_schedule_gc_links();
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci/*
2648c2ecf20Sopenharmony_ci * Build the next index key chunk.
2658c2ecf20Sopenharmony_ci *
2668c2ecf20Sopenharmony_ci * We return it one word-sized chunk at a time.
2678c2ecf20Sopenharmony_ci */
2688c2ecf20Sopenharmony_cistatic unsigned long keyring_get_key_chunk(const void *data, int level)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	const struct keyring_index_key *index_key = data;
2718c2ecf20Sopenharmony_ci	unsigned long chunk = 0;
2728c2ecf20Sopenharmony_ci	const u8 *d;
2738c2ecf20Sopenharmony_ci	int desc_len = index_key->desc_len, n = sizeof(chunk);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	level /= ASSOC_ARRAY_KEY_CHUNK_SIZE;
2768c2ecf20Sopenharmony_ci	switch (level) {
2778c2ecf20Sopenharmony_ci	case 0:
2788c2ecf20Sopenharmony_ci		return index_key->hash;
2798c2ecf20Sopenharmony_ci	case 1:
2808c2ecf20Sopenharmony_ci		return index_key->x;
2818c2ecf20Sopenharmony_ci	case 2:
2828c2ecf20Sopenharmony_ci		return (unsigned long)index_key->type;
2838c2ecf20Sopenharmony_ci	case 3:
2848c2ecf20Sopenharmony_ci		return (unsigned long)index_key->domain_tag;
2858c2ecf20Sopenharmony_ci	default:
2868c2ecf20Sopenharmony_ci		level -= 4;
2878c2ecf20Sopenharmony_ci		if (desc_len <= sizeof(index_key->desc))
2888c2ecf20Sopenharmony_ci			return 0;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		d = index_key->description + sizeof(index_key->desc);
2918c2ecf20Sopenharmony_ci		d += level * sizeof(long);
2928c2ecf20Sopenharmony_ci		desc_len -= sizeof(index_key->desc);
2938c2ecf20Sopenharmony_ci		if (desc_len > n)
2948c2ecf20Sopenharmony_ci			desc_len = n;
2958c2ecf20Sopenharmony_ci		do {
2968c2ecf20Sopenharmony_ci			chunk <<= 8;
2978c2ecf20Sopenharmony_ci			chunk |= *d++;
2988c2ecf20Sopenharmony_ci		} while (--desc_len > 0);
2998c2ecf20Sopenharmony_ci		return chunk;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic unsigned long keyring_get_object_key_chunk(const void *object, int level)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	const struct key *key = keyring_ptr_to_key(object);
3068c2ecf20Sopenharmony_ci	return keyring_get_key_chunk(&key->index_key, level);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic bool keyring_compare_object(const void *object, const void *data)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	const struct keyring_index_key *index_key = data;
3128c2ecf20Sopenharmony_ci	const struct key *key = keyring_ptr_to_key(object);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	return key->index_key.type == index_key->type &&
3158c2ecf20Sopenharmony_ci		key->index_key.domain_tag == index_key->domain_tag &&
3168c2ecf20Sopenharmony_ci		key->index_key.desc_len == index_key->desc_len &&
3178c2ecf20Sopenharmony_ci		memcmp(key->index_key.description, index_key->description,
3188c2ecf20Sopenharmony_ci		       index_key->desc_len) == 0;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci/*
3228c2ecf20Sopenharmony_ci * Compare the index keys of a pair of objects and determine the bit position
3238c2ecf20Sopenharmony_ci * at which they differ - if they differ.
3248c2ecf20Sopenharmony_ci */
3258c2ecf20Sopenharmony_cistatic int keyring_diff_objects(const void *object, const void *data)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	const struct key *key_a = keyring_ptr_to_key(object);
3288c2ecf20Sopenharmony_ci	const struct keyring_index_key *a = &key_a->index_key;
3298c2ecf20Sopenharmony_ci	const struct keyring_index_key *b = data;
3308c2ecf20Sopenharmony_ci	unsigned long seg_a, seg_b;
3318c2ecf20Sopenharmony_ci	int level, i;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	level = 0;
3348c2ecf20Sopenharmony_ci	seg_a = a->hash;
3358c2ecf20Sopenharmony_ci	seg_b = b->hash;
3368c2ecf20Sopenharmony_ci	if ((seg_a ^ seg_b) != 0)
3378c2ecf20Sopenharmony_ci		goto differ;
3388c2ecf20Sopenharmony_ci	level += ASSOC_ARRAY_KEY_CHUNK_SIZE / 8;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* The number of bits contributed by the hash is controlled by a
3418c2ecf20Sopenharmony_ci	 * constant in the assoc_array headers.  Everything else thereafter we
3428c2ecf20Sopenharmony_ci	 * can deal with as being machine word-size dependent.
3438c2ecf20Sopenharmony_ci	 */
3448c2ecf20Sopenharmony_ci	seg_a = a->x;
3458c2ecf20Sopenharmony_ci	seg_b = b->x;
3468c2ecf20Sopenharmony_ci	if ((seg_a ^ seg_b) != 0)
3478c2ecf20Sopenharmony_ci		goto differ;
3488c2ecf20Sopenharmony_ci	level += sizeof(unsigned long);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* The next bit may not work on big endian */
3518c2ecf20Sopenharmony_ci	seg_a = (unsigned long)a->type;
3528c2ecf20Sopenharmony_ci	seg_b = (unsigned long)b->type;
3538c2ecf20Sopenharmony_ci	if ((seg_a ^ seg_b) != 0)
3548c2ecf20Sopenharmony_ci		goto differ;
3558c2ecf20Sopenharmony_ci	level += sizeof(unsigned long);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	seg_a = (unsigned long)a->domain_tag;
3588c2ecf20Sopenharmony_ci	seg_b = (unsigned long)b->domain_tag;
3598c2ecf20Sopenharmony_ci	if ((seg_a ^ seg_b) != 0)
3608c2ecf20Sopenharmony_ci		goto differ;
3618c2ecf20Sopenharmony_ci	level += sizeof(unsigned long);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	i = sizeof(a->desc);
3648c2ecf20Sopenharmony_ci	if (a->desc_len <= i)
3658c2ecf20Sopenharmony_ci		goto same;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	for (; i < a->desc_len; i++) {
3688c2ecf20Sopenharmony_ci		seg_a = *(unsigned char *)(a->description + i);
3698c2ecf20Sopenharmony_ci		seg_b = *(unsigned char *)(b->description + i);
3708c2ecf20Sopenharmony_ci		if ((seg_a ^ seg_b) != 0)
3718c2ecf20Sopenharmony_ci			goto differ_plus_i;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cisame:
3758c2ecf20Sopenharmony_ci	return -1;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cidiffer_plus_i:
3788c2ecf20Sopenharmony_ci	level += i;
3798c2ecf20Sopenharmony_cidiffer:
3808c2ecf20Sopenharmony_ci	i = level * 8 + __ffs(seg_a ^ seg_b);
3818c2ecf20Sopenharmony_ci	return i;
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci/*
3858c2ecf20Sopenharmony_ci * Free an object after stripping the keyring flag off of the pointer.
3868c2ecf20Sopenharmony_ci */
3878c2ecf20Sopenharmony_cistatic void keyring_free_object(void *object)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	key_put(keyring_ptr_to_key(object));
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci/*
3938c2ecf20Sopenharmony_ci * Operations for keyring management by the index-tree routines.
3948c2ecf20Sopenharmony_ci */
3958c2ecf20Sopenharmony_cistatic const struct assoc_array_ops keyring_assoc_array_ops = {
3968c2ecf20Sopenharmony_ci	.get_key_chunk		= keyring_get_key_chunk,
3978c2ecf20Sopenharmony_ci	.get_object_key_chunk	= keyring_get_object_key_chunk,
3988c2ecf20Sopenharmony_ci	.compare_object		= keyring_compare_object,
3998c2ecf20Sopenharmony_ci	.diff_objects		= keyring_diff_objects,
4008c2ecf20Sopenharmony_ci	.free_object		= keyring_free_object,
4018c2ecf20Sopenharmony_ci};
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci/*
4048c2ecf20Sopenharmony_ci * Clean up a keyring when it is destroyed.  Unpublish its name if it had one
4058c2ecf20Sopenharmony_ci * and dispose of its data.
4068c2ecf20Sopenharmony_ci *
4078c2ecf20Sopenharmony_ci * The garbage collector detects the final key_put(), removes the keyring from
4088c2ecf20Sopenharmony_ci * the serial number tree and then does RCU synchronisation before coming here,
4098c2ecf20Sopenharmony_ci * so we shouldn't need to worry about code poking around here with the RCU
4108c2ecf20Sopenharmony_ci * readlock held by this time.
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic void keyring_destroy(struct key *keyring)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	if (keyring->description) {
4158c2ecf20Sopenharmony_ci		write_lock(&keyring_name_lock);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		if (keyring->name_link.next != NULL &&
4188c2ecf20Sopenharmony_ci		    !list_empty(&keyring->name_link))
4198c2ecf20Sopenharmony_ci			list_del(&keyring->name_link);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci		write_unlock(&keyring_name_lock);
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (keyring->restrict_link) {
4258c2ecf20Sopenharmony_ci		struct key_restriction *keyres = keyring->restrict_link;
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci		key_put(keyres->key);
4288c2ecf20Sopenharmony_ci		kfree(keyres);
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	assoc_array_destroy(&keyring->keys, &keyring_assoc_array_ops);
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci/*
4358c2ecf20Sopenharmony_ci * Describe a keyring for /proc.
4368c2ecf20Sopenharmony_ci */
4378c2ecf20Sopenharmony_cistatic void keyring_describe(const struct key *keyring, struct seq_file *m)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	if (keyring->description)
4408c2ecf20Sopenharmony_ci		seq_puts(m, keyring->description);
4418c2ecf20Sopenharmony_ci	else
4428c2ecf20Sopenharmony_ci		seq_puts(m, "[anon]");
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (key_is_positive(keyring)) {
4458c2ecf20Sopenharmony_ci		if (keyring->keys.nr_leaves_on_tree != 0)
4468c2ecf20Sopenharmony_ci			seq_printf(m, ": %lu", keyring->keys.nr_leaves_on_tree);
4478c2ecf20Sopenharmony_ci		else
4488c2ecf20Sopenharmony_ci			seq_puts(m, ": empty");
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistruct keyring_read_iterator_context {
4538c2ecf20Sopenharmony_ci	size_t			buflen;
4548c2ecf20Sopenharmony_ci	size_t			count;
4558c2ecf20Sopenharmony_ci	key_serial_t __user	*buffer;
4568c2ecf20Sopenharmony_ci};
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int keyring_read_iterator(const void *object, void *data)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct keyring_read_iterator_context *ctx = data;
4618c2ecf20Sopenharmony_ci	const struct key *key = keyring_ptr_to_key(object);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	kenter("{%s,%d},,{%zu/%zu}",
4648c2ecf20Sopenharmony_ci	       key->type->name, key->serial, ctx->count, ctx->buflen);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (ctx->count >= ctx->buflen)
4678c2ecf20Sopenharmony_ci		return 1;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	*ctx->buffer++ = key->serial;
4708c2ecf20Sopenharmony_ci	ctx->count += sizeof(key->serial);
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci/*
4758c2ecf20Sopenharmony_ci * Read a list of key IDs from the keyring's contents in binary form
4768c2ecf20Sopenharmony_ci *
4778c2ecf20Sopenharmony_ci * The keyring's semaphore is read-locked by the caller.  This prevents someone
4788c2ecf20Sopenharmony_ci * from modifying it under us - which could cause us to read key IDs multiple
4798c2ecf20Sopenharmony_ci * times.
4808c2ecf20Sopenharmony_ci */
4818c2ecf20Sopenharmony_cistatic long keyring_read(const struct key *keyring,
4828c2ecf20Sopenharmony_ci			 char __user *buffer, size_t buflen)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct keyring_read_iterator_context ctx;
4858c2ecf20Sopenharmony_ci	long ret;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	kenter("{%d},,%zu", key_serial(keyring), buflen);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (buflen & (sizeof(key_serial_t) - 1))
4908c2ecf20Sopenharmony_ci		return -EINVAL;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* Copy as many key IDs as fit into the buffer */
4938c2ecf20Sopenharmony_ci	if (buffer && buflen) {
4948c2ecf20Sopenharmony_ci		ctx.buffer = (key_serial_t __user *)buffer;
4958c2ecf20Sopenharmony_ci		ctx.buflen = buflen;
4968c2ecf20Sopenharmony_ci		ctx.count = 0;
4978c2ecf20Sopenharmony_ci		ret = assoc_array_iterate(&keyring->keys,
4988c2ecf20Sopenharmony_ci					  keyring_read_iterator, &ctx);
4998c2ecf20Sopenharmony_ci		if (ret < 0) {
5008c2ecf20Sopenharmony_ci			kleave(" = %ld [iterate]", ret);
5018c2ecf20Sopenharmony_ci			return ret;
5028c2ecf20Sopenharmony_ci		}
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* Return the size of the buffer needed */
5068c2ecf20Sopenharmony_ci	ret = keyring->keys.nr_leaves_on_tree * sizeof(key_serial_t);
5078c2ecf20Sopenharmony_ci	if (ret <= buflen)
5088c2ecf20Sopenharmony_ci		kleave("= %ld [ok]", ret);
5098c2ecf20Sopenharmony_ci	else
5108c2ecf20Sopenharmony_ci		kleave("= %ld [buffer too small]", ret);
5118c2ecf20Sopenharmony_ci	return ret;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci/*
5158c2ecf20Sopenharmony_ci * Allocate a keyring and link into the destination keyring.
5168c2ecf20Sopenharmony_ci */
5178c2ecf20Sopenharmony_cistruct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
5188c2ecf20Sopenharmony_ci			  const struct cred *cred, key_perm_t perm,
5198c2ecf20Sopenharmony_ci			  unsigned long flags,
5208c2ecf20Sopenharmony_ci			  struct key_restriction *restrict_link,
5218c2ecf20Sopenharmony_ci			  struct key *dest)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct key *keyring;
5248c2ecf20Sopenharmony_ci	int ret;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	keyring = key_alloc(&key_type_keyring, description,
5278c2ecf20Sopenharmony_ci			    uid, gid, cred, perm, flags, restrict_link);
5288c2ecf20Sopenharmony_ci	if (!IS_ERR(keyring)) {
5298c2ecf20Sopenharmony_ci		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
5308c2ecf20Sopenharmony_ci		if (ret < 0) {
5318c2ecf20Sopenharmony_ci			key_put(keyring);
5328c2ecf20Sopenharmony_ci			keyring = ERR_PTR(ret);
5338c2ecf20Sopenharmony_ci		}
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	return keyring;
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ciEXPORT_SYMBOL(keyring_alloc);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci/**
5418c2ecf20Sopenharmony_ci * restrict_link_reject - Give -EPERM to restrict link
5428c2ecf20Sopenharmony_ci * @keyring: The keyring being added to.
5438c2ecf20Sopenharmony_ci * @type: The type of key being added.
5448c2ecf20Sopenharmony_ci * @payload: The payload of the key intended to be added.
5458c2ecf20Sopenharmony_ci * @restriction_key: Keys providing additional data for evaluating restriction.
5468c2ecf20Sopenharmony_ci *
5478c2ecf20Sopenharmony_ci * Reject the addition of any links to a keyring.  It can be overridden by
5488c2ecf20Sopenharmony_ci * passing KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when
5498c2ecf20Sopenharmony_ci * adding a key to a keyring.
5508c2ecf20Sopenharmony_ci *
5518c2ecf20Sopenharmony_ci * This is meant to be stored in a key_restriction structure which is passed
5528c2ecf20Sopenharmony_ci * in the restrict_link parameter to keyring_alloc().
5538c2ecf20Sopenharmony_ci */
5548c2ecf20Sopenharmony_ciint restrict_link_reject(struct key *keyring,
5558c2ecf20Sopenharmony_ci			 const struct key_type *type,
5568c2ecf20Sopenharmony_ci			 const union key_payload *payload,
5578c2ecf20Sopenharmony_ci			 struct key *restriction_key)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	return -EPERM;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci/*
5638c2ecf20Sopenharmony_ci * By default, we keys found by getting an exact match on their descriptions.
5648c2ecf20Sopenharmony_ci */
5658c2ecf20Sopenharmony_cibool key_default_cmp(const struct key *key,
5668c2ecf20Sopenharmony_ci		     const struct key_match_data *match_data)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	return strcmp(key->description, match_data->raw_data) == 0;
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci/*
5728c2ecf20Sopenharmony_ci * Iteration function to consider each key found.
5738c2ecf20Sopenharmony_ci */
5748c2ecf20Sopenharmony_cistatic int keyring_search_iterator(const void *object, void *iterator_data)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct keyring_search_context *ctx = iterator_data;
5778c2ecf20Sopenharmony_ci	const struct key *key = keyring_ptr_to_key(object);
5788c2ecf20Sopenharmony_ci	unsigned long kflags = READ_ONCE(key->flags);
5798c2ecf20Sopenharmony_ci	short state = READ_ONCE(key->state);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	kenter("{%d}", key->serial);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	/* ignore keys not of this type */
5848c2ecf20Sopenharmony_ci	if (key->type != ctx->index_key.type) {
5858c2ecf20Sopenharmony_ci		kleave(" = 0 [!type]");
5868c2ecf20Sopenharmony_ci		return 0;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	/* skip invalidated, revoked and expired keys */
5908c2ecf20Sopenharmony_ci	if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
5918c2ecf20Sopenharmony_ci		time64_t expiry = READ_ONCE(key->expiry);
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		if (kflags & ((1 << KEY_FLAG_INVALIDATED) |
5948c2ecf20Sopenharmony_ci			      (1 << KEY_FLAG_REVOKED))) {
5958c2ecf20Sopenharmony_ci			ctx->result = ERR_PTR(-EKEYREVOKED);
5968c2ecf20Sopenharmony_ci			kleave(" = %d [invrev]", ctx->skipped_ret);
5978c2ecf20Sopenharmony_ci			goto skipped;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci		if (expiry && ctx->now >= expiry) {
6018c2ecf20Sopenharmony_ci			if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
6028c2ecf20Sopenharmony_ci				ctx->result = ERR_PTR(-EKEYEXPIRED);
6038c2ecf20Sopenharmony_ci			kleave(" = %d [expire]", ctx->skipped_ret);
6048c2ecf20Sopenharmony_ci			goto skipped;
6058c2ecf20Sopenharmony_ci		}
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	/* keys that don't match */
6098c2ecf20Sopenharmony_ci	if (!ctx->match_data.cmp(key, &ctx->match_data)) {
6108c2ecf20Sopenharmony_ci		kleave(" = 0 [!match]");
6118c2ecf20Sopenharmony_ci		return 0;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/* key must have search permissions */
6158c2ecf20Sopenharmony_ci	if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
6168c2ecf20Sopenharmony_ci	    key_task_permission(make_key_ref(key, ctx->possessed),
6178c2ecf20Sopenharmony_ci				ctx->cred, KEY_NEED_SEARCH) < 0) {
6188c2ecf20Sopenharmony_ci		ctx->result = ERR_PTR(-EACCES);
6198c2ecf20Sopenharmony_ci		kleave(" = %d [!perm]", ctx->skipped_ret);
6208c2ecf20Sopenharmony_ci		goto skipped;
6218c2ecf20Sopenharmony_ci	}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) {
6248c2ecf20Sopenharmony_ci		/* we set a different error code if we pass a negative key */
6258c2ecf20Sopenharmony_ci		if (state < 0) {
6268c2ecf20Sopenharmony_ci			ctx->result = ERR_PTR(state);
6278c2ecf20Sopenharmony_ci			kleave(" = %d [neg]", ctx->skipped_ret);
6288c2ecf20Sopenharmony_ci			goto skipped;
6298c2ecf20Sopenharmony_ci		}
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	/* Found */
6338c2ecf20Sopenharmony_ci	ctx->result = make_key_ref(key, ctx->possessed);
6348c2ecf20Sopenharmony_ci	kleave(" = 1 [found]");
6358c2ecf20Sopenharmony_ci	return 1;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ciskipped:
6388c2ecf20Sopenharmony_ci	return ctx->skipped_ret;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci/*
6428c2ecf20Sopenharmony_ci * Search inside a keyring for a key.  We can search by walking to it
6438c2ecf20Sopenharmony_ci * directly based on its index-key or we can iterate over the entire
6448c2ecf20Sopenharmony_ci * tree looking for it, based on the match function.
6458c2ecf20Sopenharmony_ci */
6468c2ecf20Sopenharmony_cistatic int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
6498c2ecf20Sopenharmony_ci		const void *object;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci		object = assoc_array_find(&keyring->keys,
6528c2ecf20Sopenharmony_ci					  &keyring_assoc_array_ops,
6538c2ecf20Sopenharmony_ci					  &ctx->index_key);
6548c2ecf20Sopenharmony_ci		return object ? ctx->iterator(object, ctx) : 0;
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci	return assoc_array_iterate(&keyring->keys, ctx->iterator, ctx);
6578c2ecf20Sopenharmony_ci}
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci/*
6608c2ecf20Sopenharmony_ci * Search a tree of keyrings that point to other keyrings up to the maximum
6618c2ecf20Sopenharmony_ci * depth.
6628c2ecf20Sopenharmony_ci */
6638c2ecf20Sopenharmony_cistatic bool search_nested_keyrings(struct key *keyring,
6648c2ecf20Sopenharmony_ci				   struct keyring_search_context *ctx)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	struct {
6678c2ecf20Sopenharmony_ci		struct key *keyring;
6688c2ecf20Sopenharmony_ci		struct assoc_array_node *node;
6698c2ecf20Sopenharmony_ci		int slot;
6708c2ecf20Sopenharmony_ci	} stack[KEYRING_SEARCH_MAX_DEPTH];
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	struct assoc_array_shortcut *shortcut;
6738c2ecf20Sopenharmony_ci	struct assoc_array_node *node;
6748c2ecf20Sopenharmony_ci	struct assoc_array_ptr *ptr;
6758c2ecf20Sopenharmony_ci	struct key *key;
6768c2ecf20Sopenharmony_ci	int sp = 0, slot;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	kenter("{%d},{%s,%s}",
6798c2ecf20Sopenharmony_ci	       keyring->serial,
6808c2ecf20Sopenharmony_ci	       ctx->index_key.type->name,
6818c2ecf20Sopenharmony_ci	       ctx->index_key.description);
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci#define STATE_CHECKS (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_DO_STATE_CHECK)
6848c2ecf20Sopenharmony_ci	BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
6858c2ecf20Sopenharmony_ci	       (ctx->flags & STATE_CHECKS) == STATE_CHECKS);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	if (ctx->index_key.description)
6888c2ecf20Sopenharmony_ci		key_set_index_key(&ctx->index_key);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	/* Check to see if this top-level keyring is what we are looking for
6918c2ecf20Sopenharmony_ci	 * and whether it is valid or not.
6928c2ecf20Sopenharmony_ci	 */
6938c2ecf20Sopenharmony_ci	if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
6948c2ecf20Sopenharmony_ci	    keyring_compare_object(keyring, &ctx->index_key)) {
6958c2ecf20Sopenharmony_ci		ctx->skipped_ret = 2;
6968c2ecf20Sopenharmony_ci		switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) {
6978c2ecf20Sopenharmony_ci		case 1:
6988c2ecf20Sopenharmony_ci			goto found;
6998c2ecf20Sopenharmony_ci		case 2:
7008c2ecf20Sopenharmony_ci			return false;
7018c2ecf20Sopenharmony_ci		default:
7028c2ecf20Sopenharmony_ci			break;
7038c2ecf20Sopenharmony_ci		}
7048c2ecf20Sopenharmony_ci	}
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	ctx->skipped_ret = 0;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* Start processing a new keyring */
7098c2ecf20Sopenharmony_cidescend_to_keyring:
7108c2ecf20Sopenharmony_ci	kdebug("descend to %d", keyring->serial);
7118c2ecf20Sopenharmony_ci	if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
7128c2ecf20Sopenharmony_ci			      (1 << KEY_FLAG_REVOKED)))
7138c2ecf20Sopenharmony_ci		goto not_this_keyring;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* Search through the keys in this keyring before its searching its
7168c2ecf20Sopenharmony_ci	 * subtrees.
7178c2ecf20Sopenharmony_ci	 */
7188c2ecf20Sopenharmony_ci	if (search_keyring(keyring, ctx))
7198c2ecf20Sopenharmony_ci		goto found;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	/* Then manually iterate through the keyrings nested in this one.
7228c2ecf20Sopenharmony_ci	 *
7238c2ecf20Sopenharmony_ci	 * Start from the root node of the index tree.  Because of the way the
7248c2ecf20Sopenharmony_ci	 * hash function has been set up, keyrings cluster on the leftmost
7258c2ecf20Sopenharmony_ci	 * branch of the root node (root slot 0) or in the root node itself.
7268c2ecf20Sopenharmony_ci	 * Non-keyrings avoid the leftmost branch of the root entirely (root
7278c2ecf20Sopenharmony_ci	 * slots 1-15).
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	if (!(ctx->flags & KEYRING_SEARCH_RECURSE))
7308c2ecf20Sopenharmony_ci		goto not_this_keyring;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	ptr = READ_ONCE(keyring->keys.root);
7338c2ecf20Sopenharmony_ci	if (!ptr)
7348c2ecf20Sopenharmony_ci		goto not_this_keyring;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci	if (assoc_array_ptr_is_shortcut(ptr)) {
7378c2ecf20Sopenharmony_ci		/* If the root is a shortcut, either the keyring only contains
7388c2ecf20Sopenharmony_ci		 * keyring pointers (everything clusters behind root slot 0) or
7398c2ecf20Sopenharmony_ci		 * doesn't contain any keyring pointers.
7408c2ecf20Sopenharmony_ci		 */
7418c2ecf20Sopenharmony_ci		shortcut = assoc_array_ptr_to_shortcut(ptr);
7428c2ecf20Sopenharmony_ci		if ((shortcut->index_key[0] & ASSOC_ARRAY_FAN_MASK) != 0)
7438c2ecf20Sopenharmony_ci			goto not_this_keyring;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci		ptr = READ_ONCE(shortcut->next_node);
7468c2ecf20Sopenharmony_ci		node = assoc_array_ptr_to_node(ptr);
7478c2ecf20Sopenharmony_ci		goto begin_node;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	node = assoc_array_ptr_to_node(ptr);
7518c2ecf20Sopenharmony_ci	ptr = node->slots[0];
7528c2ecf20Sopenharmony_ci	if (!assoc_array_ptr_is_meta(ptr))
7538c2ecf20Sopenharmony_ci		goto begin_node;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cidescend_to_node:
7568c2ecf20Sopenharmony_ci	/* Descend to a more distal node in this keyring's content tree and go
7578c2ecf20Sopenharmony_ci	 * through that.
7588c2ecf20Sopenharmony_ci	 */
7598c2ecf20Sopenharmony_ci	kdebug("descend");
7608c2ecf20Sopenharmony_ci	if (assoc_array_ptr_is_shortcut(ptr)) {
7618c2ecf20Sopenharmony_ci		shortcut = assoc_array_ptr_to_shortcut(ptr);
7628c2ecf20Sopenharmony_ci		ptr = READ_ONCE(shortcut->next_node);
7638c2ecf20Sopenharmony_ci		BUG_ON(!assoc_array_ptr_is_node(ptr));
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci	node = assoc_array_ptr_to_node(ptr);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_cibegin_node:
7688c2ecf20Sopenharmony_ci	kdebug("begin_node");
7698c2ecf20Sopenharmony_ci	slot = 0;
7708c2ecf20Sopenharmony_ciascend_to_node:
7718c2ecf20Sopenharmony_ci	/* Go through the slots in a node */
7728c2ecf20Sopenharmony_ci	for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
7738c2ecf20Sopenharmony_ci		ptr = READ_ONCE(node->slots[slot]);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		if (assoc_array_ptr_is_meta(ptr) && node->back_pointer)
7768c2ecf20Sopenharmony_ci			goto descend_to_node;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		if (!keyring_ptr_is_keyring(ptr))
7798c2ecf20Sopenharmony_ci			continue;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci		key = keyring_ptr_to_key(ptr);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		if (sp >= KEYRING_SEARCH_MAX_DEPTH) {
7848c2ecf20Sopenharmony_ci			if (ctx->flags & KEYRING_SEARCH_DETECT_TOO_DEEP) {
7858c2ecf20Sopenharmony_ci				ctx->result = ERR_PTR(-ELOOP);
7868c2ecf20Sopenharmony_ci				return false;
7878c2ecf20Sopenharmony_ci			}
7888c2ecf20Sopenharmony_ci			goto not_this_keyring;
7898c2ecf20Sopenharmony_ci		}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		/* Search a nested keyring */
7928c2ecf20Sopenharmony_ci		if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) &&
7938c2ecf20Sopenharmony_ci		    key_task_permission(make_key_ref(key, ctx->possessed),
7948c2ecf20Sopenharmony_ci					ctx->cred, KEY_NEED_SEARCH) < 0)
7958c2ecf20Sopenharmony_ci			continue;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		/* stack the current position */
7988c2ecf20Sopenharmony_ci		stack[sp].keyring = keyring;
7998c2ecf20Sopenharmony_ci		stack[sp].node = node;
8008c2ecf20Sopenharmony_ci		stack[sp].slot = slot;
8018c2ecf20Sopenharmony_ci		sp++;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci		/* begin again with the new keyring */
8048c2ecf20Sopenharmony_ci		keyring = key;
8058c2ecf20Sopenharmony_ci		goto descend_to_keyring;
8068c2ecf20Sopenharmony_ci	}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	/* We've dealt with all the slots in the current node, so now we need
8098c2ecf20Sopenharmony_ci	 * to ascend to the parent and continue processing there.
8108c2ecf20Sopenharmony_ci	 */
8118c2ecf20Sopenharmony_ci	ptr = READ_ONCE(node->back_pointer);
8128c2ecf20Sopenharmony_ci	slot = node->parent_slot;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci	if (ptr && assoc_array_ptr_is_shortcut(ptr)) {
8158c2ecf20Sopenharmony_ci		shortcut = assoc_array_ptr_to_shortcut(ptr);
8168c2ecf20Sopenharmony_ci		ptr = READ_ONCE(shortcut->back_pointer);
8178c2ecf20Sopenharmony_ci		slot = shortcut->parent_slot;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci	if (!ptr)
8208c2ecf20Sopenharmony_ci		goto not_this_keyring;
8218c2ecf20Sopenharmony_ci	node = assoc_array_ptr_to_node(ptr);
8228c2ecf20Sopenharmony_ci	slot++;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	/* If we've ascended to the root (zero backpointer), we must have just
8258c2ecf20Sopenharmony_ci	 * finished processing the leftmost branch rather than the root slots -
8268c2ecf20Sopenharmony_ci	 * so there can't be any more keyrings for us to find.
8278c2ecf20Sopenharmony_ci	 */
8288c2ecf20Sopenharmony_ci	if (node->back_pointer) {
8298c2ecf20Sopenharmony_ci		kdebug("ascend %d", slot);
8308c2ecf20Sopenharmony_ci		goto ascend_to_node;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	/* The keyring we're looking at was disqualified or didn't contain a
8348c2ecf20Sopenharmony_ci	 * matching key.
8358c2ecf20Sopenharmony_ci	 */
8368c2ecf20Sopenharmony_cinot_this_keyring:
8378c2ecf20Sopenharmony_ci	kdebug("not_this_keyring %d", sp);
8388c2ecf20Sopenharmony_ci	if (sp <= 0) {
8398c2ecf20Sopenharmony_ci		kleave(" = false");
8408c2ecf20Sopenharmony_ci		return false;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	/* Resume the processing of a keyring higher up in the tree */
8448c2ecf20Sopenharmony_ci	sp--;
8458c2ecf20Sopenharmony_ci	keyring = stack[sp].keyring;
8468c2ecf20Sopenharmony_ci	node = stack[sp].node;
8478c2ecf20Sopenharmony_ci	slot = stack[sp].slot + 1;
8488c2ecf20Sopenharmony_ci	kdebug("ascend to %d [%d]", keyring->serial, slot);
8498c2ecf20Sopenharmony_ci	goto ascend_to_node;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* We found a viable match */
8528c2ecf20Sopenharmony_cifound:
8538c2ecf20Sopenharmony_ci	key = key_ref_to_ptr(ctx->result);
8548c2ecf20Sopenharmony_ci	key_check(key);
8558c2ecf20Sopenharmony_ci	if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) {
8568c2ecf20Sopenharmony_ci		key->last_used_at = ctx->now;
8578c2ecf20Sopenharmony_ci		keyring->last_used_at = ctx->now;
8588c2ecf20Sopenharmony_ci		while (sp > 0)
8598c2ecf20Sopenharmony_ci			stack[--sp].keyring->last_used_at = ctx->now;
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci	kleave(" = true");
8628c2ecf20Sopenharmony_ci	return true;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/**
8668c2ecf20Sopenharmony_ci * keyring_search_rcu - Search a keyring tree for a matching key under RCU
8678c2ecf20Sopenharmony_ci * @keyring_ref: A pointer to the keyring with possession indicator.
8688c2ecf20Sopenharmony_ci * @ctx: The keyring search context.
8698c2ecf20Sopenharmony_ci *
8708c2ecf20Sopenharmony_ci * Search the supplied keyring tree for a key that matches the criteria given.
8718c2ecf20Sopenharmony_ci * The root keyring and any linked keyrings must grant Search permission to the
8728c2ecf20Sopenharmony_ci * caller to be searchable and keys can only be found if they too grant Search
8738c2ecf20Sopenharmony_ci * to the caller. The possession flag on the root keyring pointer controls use
8748c2ecf20Sopenharmony_ci * of the possessor bits in permissions checking of the entire tree.  In
8758c2ecf20Sopenharmony_ci * addition, the LSM gets to forbid keyring searches and key matches.
8768c2ecf20Sopenharmony_ci *
8778c2ecf20Sopenharmony_ci * The search is performed as a breadth-then-depth search up to the prescribed
8788c2ecf20Sopenharmony_ci * limit (KEYRING_SEARCH_MAX_DEPTH).  The caller must hold the RCU read lock to
8798c2ecf20Sopenharmony_ci * prevent keyrings from being destroyed or rearranged whilst they are being
8808c2ecf20Sopenharmony_ci * searched.
8818c2ecf20Sopenharmony_ci *
8828c2ecf20Sopenharmony_ci * Keys are matched to the type provided and are then filtered by the match
8838c2ecf20Sopenharmony_ci * function, which is given the description to use in any way it sees fit.  The
8848c2ecf20Sopenharmony_ci * match function may use any attributes of a key that it wishes to to
8858c2ecf20Sopenharmony_ci * determine the match.  Normally the match function from the key type would be
8868c2ecf20Sopenharmony_ci * used.
8878c2ecf20Sopenharmony_ci *
8888c2ecf20Sopenharmony_ci * RCU can be used to prevent the keyring key lists from disappearing without
8898c2ecf20Sopenharmony_ci * the need to take lots of locks.
8908c2ecf20Sopenharmony_ci *
8918c2ecf20Sopenharmony_ci * Returns a pointer to the found key and increments the key usage count if
8928c2ecf20Sopenharmony_ci * successful; -EAGAIN if no matching keys were found, or if expired or revoked
8938c2ecf20Sopenharmony_ci * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the
8948c2ecf20Sopenharmony_ci * specified keyring wasn't a keyring.
8958c2ecf20Sopenharmony_ci *
8968c2ecf20Sopenharmony_ci * In the case of a successful return, the possession attribute from
8978c2ecf20Sopenharmony_ci * @keyring_ref is propagated to the returned key reference.
8988c2ecf20Sopenharmony_ci */
8998c2ecf20Sopenharmony_cikey_ref_t keyring_search_rcu(key_ref_t keyring_ref,
9008c2ecf20Sopenharmony_ci			     struct keyring_search_context *ctx)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	struct key *keyring;
9038c2ecf20Sopenharmony_ci	long err;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	ctx->iterator = keyring_search_iterator;
9068c2ecf20Sopenharmony_ci	ctx->possessed = is_key_possessed(keyring_ref);
9078c2ecf20Sopenharmony_ci	ctx->result = ERR_PTR(-EAGAIN);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	keyring = key_ref_to_ptr(keyring_ref);
9108c2ecf20Sopenharmony_ci	key_check(keyring);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (keyring->type != &key_type_keyring)
9138c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOTDIR);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) {
9168c2ecf20Sopenharmony_ci		err = key_task_permission(keyring_ref, ctx->cred, KEY_NEED_SEARCH);
9178c2ecf20Sopenharmony_ci		if (err < 0)
9188c2ecf20Sopenharmony_ci			return ERR_PTR(err);
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	ctx->now = ktime_get_real_seconds();
9228c2ecf20Sopenharmony_ci	if (search_nested_keyrings(keyring, ctx))
9238c2ecf20Sopenharmony_ci		__key_get(key_ref_to_ptr(ctx->result));
9248c2ecf20Sopenharmony_ci	return ctx->result;
9258c2ecf20Sopenharmony_ci}
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci/**
9288c2ecf20Sopenharmony_ci * keyring_search - Search the supplied keyring tree for a matching key
9298c2ecf20Sopenharmony_ci * @keyring: The root of the keyring tree to be searched.
9308c2ecf20Sopenharmony_ci * @type: The type of keyring we want to find.
9318c2ecf20Sopenharmony_ci * @description: The name of the keyring we want to find.
9328c2ecf20Sopenharmony_ci * @recurse: True to search the children of @keyring also
9338c2ecf20Sopenharmony_ci *
9348c2ecf20Sopenharmony_ci * As keyring_search_rcu() above, but using the current task's credentials and
9358c2ecf20Sopenharmony_ci * type's default matching function and preferred search method.
9368c2ecf20Sopenharmony_ci */
9378c2ecf20Sopenharmony_cikey_ref_t keyring_search(key_ref_t keyring,
9388c2ecf20Sopenharmony_ci			 struct key_type *type,
9398c2ecf20Sopenharmony_ci			 const char *description,
9408c2ecf20Sopenharmony_ci			 bool recurse)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	struct keyring_search_context ctx = {
9438c2ecf20Sopenharmony_ci		.index_key.type		= type,
9448c2ecf20Sopenharmony_ci		.index_key.description	= description,
9458c2ecf20Sopenharmony_ci		.index_key.desc_len	= strlen(description),
9468c2ecf20Sopenharmony_ci		.cred			= current_cred(),
9478c2ecf20Sopenharmony_ci		.match_data.cmp		= key_default_cmp,
9488c2ecf20Sopenharmony_ci		.match_data.raw_data	= description,
9498c2ecf20Sopenharmony_ci		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
9508c2ecf20Sopenharmony_ci		.flags			= KEYRING_SEARCH_DO_STATE_CHECK,
9518c2ecf20Sopenharmony_ci	};
9528c2ecf20Sopenharmony_ci	key_ref_t key;
9538c2ecf20Sopenharmony_ci	int ret;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	if (recurse)
9568c2ecf20Sopenharmony_ci		ctx.flags |= KEYRING_SEARCH_RECURSE;
9578c2ecf20Sopenharmony_ci	if (type->match_preparse) {
9588c2ecf20Sopenharmony_ci		ret = type->match_preparse(&ctx.match_data);
9598c2ecf20Sopenharmony_ci		if (ret < 0)
9608c2ecf20Sopenharmony_ci			return ERR_PTR(ret);
9618c2ecf20Sopenharmony_ci	}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	rcu_read_lock();
9648c2ecf20Sopenharmony_ci	key = keyring_search_rcu(keyring, &ctx);
9658c2ecf20Sopenharmony_ci	rcu_read_unlock();
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	if (type->match_free)
9688c2ecf20Sopenharmony_ci		type->match_free(&ctx.match_data);
9698c2ecf20Sopenharmony_ci	return key;
9708c2ecf20Sopenharmony_ci}
9718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(keyring_search);
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistatic struct key_restriction *keyring_restriction_alloc(
9748c2ecf20Sopenharmony_ci	key_restrict_link_func_t check)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	struct key_restriction *keyres =
9778c2ecf20Sopenharmony_ci		kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (!keyres)
9808c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	keyres->check = check;
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	return keyres;
9858c2ecf20Sopenharmony_ci}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci/*
9888c2ecf20Sopenharmony_ci * Semaphore to serialise restriction setup to prevent reference count
9898c2ecf20Sopenharmony_ci * cycles through restriction key pointers.
9908c2ecf20Sopenharmony_ci */
9918c2ecf20Sopenharmony_cistatic DECLARE_RWSEM(keyring_serialise_restrict_sem);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci/*
9948c2ecf20Sopenharmony_ci * Check for restriction cycles that would prevent keyring garbage collection.
9958c2ecf20Sopenharmony_ci * keyring_serialise_restrict_sem must be held.
9968c2ecf20Sopenharmony_ci */
9978c2ecf20Sopenharmony_cistatic bool keyring_detect_restriction_cycle(const struct key *dest_keyring,
9988c2ecf20Sopenharmony_ci					     struct key_restriction *keyres)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	while (keyres && keyres->key &&
10018c2ecf20Sopenharmony_ci	       keyres->key->type == &key_type_keyring) {
10028c2ecf20Sopenharmony_ci		if (keyres->key == dest_keyring)
10038c2ecf20Sopenharmony_ci			return true;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		keyres = keyres->key->restrict_link;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	return false;
10098c2ecf20Sopenharmony_ci}
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci/**
10128c2ecf20Sopenharmony_ci * keyring_restrict - Look up and apply a restriction to a keyring
10138c2ecf20Sopenharmony_ci * @keyring_ref: The keyring to be restricted
10148c2ecf20Sopenharmony_ci * @type: The key type that will provide the restriction checker.
10158c2ecf20Sopenharmony_ci * @restriction: The restriction options to apply to the keyring
10168c2ecf20Sopenharmony_ci *
10178c2ecf20Sopenharmony_ci * Look up a keyring and apply a restriction to it.  The restriction is managed
10188c2ecf20Sopenharmony_ci * by the specific key type, but can be configured by the options specified in
10198c2ecf20Sopenharmony_ci * the restriction string.
10208c2ecf20Sopenharmony_ci */
10218c2ecf20Sopenharmony_ciint keyring_restrict(key_ref_t keyring_ref, const char *type,
10228c2ecf20Sopenharmony_ci		     const char *restriction)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	struct key *keyring;
10258c2ecf20Sopenharmony_ci	struct key_type *restrict_type = NULL;
10268c2ecf20Sopenharmony_ci	struct key_restriction *restrict_link;
10278c2ecf20Sopenharmony_ci	int ret = 0;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	keyring = key_ref_to_ptr(keyring_ref);
10308c2ecf20Sopenharmony_ci	key_check(keyring);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (keyring->type != &key_type_keyring)
10338c2ecf20Sopenharmony_ci		return -ENOTDIR;
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	if (!type) {
10368c2ecf20Sopenharmony_ci		restrict_link = keyring_restriction_alloc(restrict_link_reject);
10378c2ecf20Sopenharmony_ci	} else {
10388c2ecf20Sopenharmony_ci		restrict_type = key_type_lookup(type);
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci		if (IS_ERR(restrict_type))
10418c2ecf20Sopenharmony_ci			return PTR_ERR(restrict_type);
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci		if (!restrict_type->lookup_restriction) {
10448c2ecf20Sopenharmony_ci			ret = -ENOENT;
10458c2ecf20Sopenharmony_ci			goto error;
10468c2ecf20Sopenharmony_ci		}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci		restrict_link = restrict_type->lookup_restriction(restriction);
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	if (IS_ERR(restrict_link)) {
10528c2ecf20Sopenharmony_ci		ret = PTR_ERR(restrict_link);
10538c2ecf20Sopenharmony_ci		goto error;
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	down_write(&keyring->sem);
10578c2ecf20Sopenharmony_ci	down_write(&keyring_serialise_restrict_sem);
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	if (keyring->restrict_link) {
10608c2ecf20Sopenharmony_ci		ret = -EEXIST;
10618c2ecf20Sopenharmony_ci	} else if (keyring_detect_restriction_cycle(keyring, restrict_link)) {
10628c2ecf20Sopenharmony_ci		ret = -EDEADLK;
10638c2ecf20Sopenharmony_ci	} else {
10648c2ecf20Sopenharmony_ci		keyring->restrict_link = restrict_link;
10658c2ecf20Sopenharmony_ci		notify_key(keyring, NOTIFY_KEY_SETATTR, 0);
10668c2ecf20Sopenharmony_ci	}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	up_write(&keyring_serialise_restrict_sem);
10698c2ecf20Sopenharmony_ci	up_write(&keyring->sem);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	if (ret < 0) {
10728c2ecf20Sopenharmony_ci		key_put(restrict_link->key);
10738c2ecf20Sopenharmony_ci		kfree(restrict_link);
10748c2ecf20Sopenharmony_ci	}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_cierror:
10778c2ecf20Sopenharmony_ci	if (restrict_type)
10788c2ecf20Sopenharmony_ci		key_type_put(restrict_type);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	return ret;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(keyring_restrict);
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci/*
10858c2ecf20Sopenharmony_ci * Search the given keyring for a key that might be updated.
10868c2ecf20Sopenharmony_ci *
10878c2ecf20Sopenharmony_ci * The caller must guarantee that the keyring is a keyring and that the
10888c2ecf20Sopenharmony_ci * permission is granted to modify the keyring as no check is made here.  The
10898c2ecf20Sopenharmony_ci * caller must also hold a lock on the keyring semaphore.
10908c2ecf20Sopenharmony_ci *
10918c2ecf20Sopenharmony_ci * Returns a pointer to the found key with usage count incremented if
10928c2ecf20Sopenharmony_ci * successful and returns NULL if not found.  Revoked and invalidated keys are
10938c2ecf20Sopenharmony_ci * skipped over.
10948c2ecf20Sopenharmony_ci *
10958c2ecf20Sopenharmony_ci * If successful, the possession indicator is propagated from the keyring ref
10968c2ecf20Sopenharmony_ci * to the returned key reference.
10978c2ecf20Sopenharmony_ci */
10988c2ecf20Sopenharmony_cikey_ref_t find_key_to_update(key_ref_t keyring_ref,
10998c2ecf20Sopenharmony_ci			     const struct keyring_index_key *index_key)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	struct key *keyring, *key;
11028c2ecf20Sopenharmony_ci	const void *object;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	keyring = key_ref_to_ptr(keyring_ref);
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	kenter("{%d},{%s,%s}",
11078c2ecf20Sopenharmony_ci	       keyring->serial, index_key->type->name, index_key->description);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	object = assoc_array_find(&keyring->keys, &keyring_assoc_array_ops,
11108c2ecf20Sopenharmony_ci				  index_key);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	if (object)
11138c2ecf20Sopenharmony_ci		goto found;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	kleave(" = NULL");
11168c2ecf20Sopenharmony_ci	return NULL;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_cifound:
11198c2ecf20Sopenharmony_ci	key = keyring_ptr_to_key(object);
11208c2ecf20Sopenharmony_ci	if (key->flags & ((1 << KEY_FLAG_INVALIDATED) |
11218c2ecf20Sopenharmony_ci			  (1 << KEY_FLAG_REVOKED))) {
11228c2ecf20Sopenharmony_ci		kleave(" = NULL [x]");
11238c2ecf20Sopenharmony_ci		return NULL;
11248c2ecf20Sopenharmony_ci	}
11258c2ecf20Sopenharmony_ci	__key_get(key);
11268c2ecf20Sopenharmony_ci	kleave(" = {%d}", key->serial);
11278c2ecf20Sopenharmony_ci	return make_key_ref(key, is_key_possessed(keyring_ref));
11288c2ecf20Sopenharmony_ci}
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci/*
11318c2ecf20Sopenharmony_ci * Find a keyring with the specified name.
11328c2ecf20Sopenharmony_ci *
11338c2ecf20Sopenharmony_ci * Only keyrings that have nonzero refcount, are not revoked, and are owned by a
11348c2ecf20Sopenharmony_ci * user in the current user namespace are considered.  If @uid_keyring is %true,
11358c2ecf20Sopenharmony_ci * the keyring additionally must have been allocated as a user or user session
11368c2ecf20Sopenharmony_ci * keyring; otherwise, it must grant Search permission directly to the caller.
11378c2ecf20Sopenharmony_ci *
11388c2ecf20Sopenharmony_ci * Returns a pointer to the keyring with the keyring's refcount having being
11398c2ecf20Sopenharmony_ci * incremented on success.  -ENOKEY is returned if a key could not be found.
11408c2ecf20Sopenharmony_ci */
11418c2ecf20Sopenharmony_cistruct key *find_keyring_by_name(const char *name, bool uid_keyring)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	struct user_namespace *ns = current_user_ns();
11448c2ecf20Sopenharmony_ci	struct key *keyring;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	if (!name)
11478c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	read_lock(&keyring_name_lock);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	/* Search this hash bucket for a keyring with a matching name that
11528c2ecf20Sopenharmony_ci	 * grants Search permission and that hasn't been revoked
11538c2ecf20Sopenharmony_ci	 */
11548c2ecf20Sopenharmony_ci	list_for_each_entry(keyring, &ns->keyring_name_list, name_link) {
11558c2ecf20Sopenharmony_ci		if (!kuid_has_mapping(ns, keyring->user->uid))
11568c2ecf20Sopenharmony_ci			continue;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci		if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
11598c2ecf20Sopenharmony_ci			continue;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci		if (strcmp(keyring->description, name) != 0)
11628c2ecf20Sopenharmony_ci			continue;
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci		if (uid_keyring) {
11658c2ecf20Sopenharmony_ci			if (!test_bit(KEY_FLAG_UID_KEYRING,
11668c2ecf20Sopenharmony_ci				      &keyring->flags))
11678c2ecf20Sopenharmony_ci				continue;
11688c2ecf20Sopenharmony_ci		} else {
11698c2ecf20Sopenharmony_ci			if (key_permission(make_key_ref(keyring, 0),
11708c2ecf20Sopenharmony_ci					   KEY_NEED_SEARCH) < 0)
11718c2ecf20Sopenharmony_ci				continue;
11728c2ecf20Sopenharmony_ci		}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci		/* we've got a match but we might end up racing with
11758c2ecf20Sopenharmony_ci		 * key_cleanup() if the keyring is currently 'dead'
11768c2ecf20Sopenharmony_ci		 * (ie. it has a zero usage count) */
11778c2ecf20Sopenharmony_ci		if (!refcount_inc_not_zero(&keyring->usage))
11788c2ecf20Sopenharmony_ci			continue;
11798c2ecf20Sopenharmony_ci		keyring->last_used_at = ktime_get_real_seconds();
11808c2ecf20Sopenharmony_ci		goto out;
11818c2ecf20Sopenharmony_ci	}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	keyring = ERR_PTR(-ENOKEY);
11848c2ecf20Sopenharmony_ciout:
11858c2ecf20Sopenharmony_ci	read_unlock(&keyring_name_lock);
11868c2ecf20Sopenharmony_ci	return keyring;
11878c2ecf20Sopenharmony_ci}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_cistatic int keyring_detect_cycle_iterator(const void *object,
11908c2ecf20Sopenharmony_ci					 void *iterator_data)
11918c2ecf20Sopenharmony_ci{
11928c2ecf20Sopenharmony_ci	struct keyring_search_context *ctx = iterator_data;
11938c2ecf20Sopenharmony_ci	const struct key *key = keyring_ptr_to_key(object);
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	kenter("{%d}", key->serial);
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	/* We might get a keyring with matching index-key that is nonetheless a
11988c2ecf20Sopenharmony_ci	 * different keyring. */
11998c2ecf20Sopenharmony_ci	if (key != ctx->match_data.raw_data)
12008c2ecf20Sopenharmony_ci		return 0;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	ctx->result = ERR_PTR(-EDEADLK);
12038c2ecf20Sopenharmony_ci	return 1;
12048c2ecf20Sopenharmony_ci}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci/*
12078c2ecf20Sopenharmony_ci * See if a cycle will will be created by inserting acyclic tree B in acyclic
12088c2ecf20Sopenharmony_ci * tree A at the topmost level (ie: as a direct child of A).
12098c2ecf20Sopenharmony_ci *
12108c2ecf20Sopenharmony_ci * Since we are adding B to A at the top level, checking for cycles should just
12118c2ecf20Sopenharmony_ci * be a matter of seeing if node A is somewhere in tree B.
12128c2ecf20Sopenharmony_ci */
12138c2ecf20Sopenharmony_cistatic int keyring_detect_cycle(struct key *A, struct key *B)
12148c2ecf20Sopenharmony_ci{
12158c2ecf20Sopenharmony_ci	struct keyring_search_context ctx = {
12168c2ecf20Sopenharmony_ci		.index_key		= A->index_key,
12178c2ecf20Sopenharmony_ci		.match_data.raw_data	= A,
12188c2ecf20Sopenharmony_ci		.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
12198c2ecf20Sopenharmony_ci		.iterator		= keyring_detect_cycle_iterator,
12208c2ecf20Sopenharmony_ci		.flags			= (KEYRING_SEARCH_NO_STATE_CHECK |
12218c2ecf20Sopenharmony_ci					   KEYRING_SEARCH_NO_UPDATE_TIME |
12228c2ecf20Sopenharmony_ci					   KEYRING_SEARCH_NO_CHECK_PERM |
12238c2ecf20Sopenharmony_ci					   KEYRING_SEARCH_DETECT_TOO_DEEP |
12248c2ecf20Sopenharmony_ci					   KEYRING_SEARCH_RECURSE),
12258c2ecf20Sopenharmony_ci	};
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	rcu_read_lock();
12288c2ecf20Sopenharmony_ci	search_nested_keyrings(B, &ctx);
12298c2ecf20Sopenharmony_ci	rcu_read_unlock();
12308c2ecf20Sopenharmony_ci	return PTR_ERR(ctx.result) == -EAGAIN ? 0 : PTR_ERR(ctx.result);
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci/*
12348c2ecf20Sopenharmony_ci * Lock keyring for link.
12358c2ecf20Sopenharmony_ci */
12368c2ecf20Sopenharmony_ciint __key_link_lock(struct key *keyring,
12378c2ecf20Sopenharmony_ci		    const struct keyring_index_key *index_key)
12388c2ecf20Sopenharmony_ci	__acquires(&keyring->sem)
12398c2ecf20Sopenharmony_ci	__acquires(&keyring_serialise_link_lock)
12408c2ecf20Sopenharmony_ci{
12418c2ecf20Sopenharmony_ci	if (keyring->type != &key_type_keyring)
12428c2ecf20Sopenharmony_ci		return -ENOTDIR;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	down_write(&keyring->sem);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	/* Serialise link/link calls to prevent parallel calls causing a cycle
12478c2ecf20Sopenharmony_ci	 * when linking two keyring in opposite orders.
12488c2ecf20Sopenharmony_ci	 */
12498c2ecf20Sopenharmony_ci	if (index_key->type == &key_type_keyring)
12508c2ecf20Sopenharmony_ci		mutex_lock(&keyring_serialise_link_lock);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	return 0;
12538c2ecf20Sopenharmony_ci}
12548c2ecf20Sopenharmony_ci
12558c2ecf20Sopenharmony_ci/*
12568c2ecf20Sopenharmony_ci * Lock keyrings for move (link/unlink combination).
12578c2ecf20Sopenharmony_ci */
12588c2ecf20Sopenharmony_ciint __key_move_lock(struct key *l_keyring, struct key *u_keyring,
12598c2ecf20Sopenharmony_ci		    const struct keyring_index_key *index_key)
12608c2ecf20Sopenharmony_ci	__acquires(&l_keyring->sem)
12618c2ecf20Sopenharmony_ci	__acquires(&u_keyring->sem)
12628c2ecf20Sopenharmony_ci	__acquires(&keyring_serialise_link_lock)
12638c2ecf20Sopenharmony_ci{
12648c2ecf20Sopenharmony_ci	if (l_keyring->type != &key_type_keyring ||
12658c2ecf20Sopenharmony_ci	    u_keyring->type != &key_type_keyring)
12668c2ecf20Sopenharmony_ci		return -ENOTDIR;
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	/* We have to be very careful here to take the keyring locks in the
12698c2ecf20Sopenharmony_ci	 * right order, lest we open ourselves to deadlocking against another
12708c2ecf20Sopenharmony_ci	 * move operation.
12718c2ecf20Sopenharmony_ci	 */
12728c2ecf20Sopenharmony_ci	if (l_keyring < u_keyring) {
12738c2ecf20Sopenharmony_ci		down_write(&l_keyring->sem);
12748c2ecf20Sopenharmony_ci		down_write_nested(&u_keyring->sem, 1);
12758c2ecf20Sopenharmony_ci	} else {
12768c2ecf20Sopenharmony_ci		down_write(&u_keyring->sem);
12778c2ecf20Sopenharmony_ci		down_write_nested(&l_keyring->sem, 1);
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	/* Serialise link/link calls to prevent parallel calls causing a cycle
12818c2ecf20Sopenharmony_ci	 * when linking two keyring in opposite orders.
12828c2ecf20Sopenharmony_ci	 */
12838c2ecf20Sopenharmony_ci	if (index_key->type == &key_type_keyring)
12848c2ecf20Sopenharmony_ci		mutex_lock(&keyring_serialise_link_lock);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	return 0;
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci/*
12908c2ecf20Sopenharmony_ci * Preallocate memory so that a key can be linked into to a keyring.
12918c2ecf20Sopenharmony_ci */
12928c2ecf20Sopenharmony_ciint __key_link_begin(struct key *keyring,
12938c2ecf20Sopenharmony_ci		     const struct keyring_index_key *index_key,
12948c2ecf20Sopenharmony_ci		     struct assoc_array_edit **_edit)
12958c2ecf20Sopenharmony_ci{
12968c2ecf20Sopenharmony_ci	struct assoc_array_edit *edit;
12978c2ecf20Sopenharmony_ci	int ret;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	kenter("%d,%s,%s,",
13008c2ecf20Sopenharmony_ci	       keyring->serial, index_key->type->name, index_key->description);
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	BUG_ON(index_key->desc_len == 0);
13038c2ecf20Sopenharmony_ci	BUG_ON(*_edit != NULL);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	*_edit = NULL;
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	ret = -EKEYREVOKED;
13088c2ecf20Sopenharmony_ci	if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
13098c2ecf20Sopenharmony_ci		goto error;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	/* Create an edit script that will insert/replace the key in the
13128c2ecf20Sopenharmony_ci	 * keyring tree.
13138c2ecf20Sopenharmony_ci	 */
13148c2ecf20Sopenharmony_ci	edit = assoc_array_insert(&keyring->keys,
13158c2ecf20Sopenharmony_ci				  &keyring_assoc_array_ops,
13168c2ecf20Sopenharmony_ci				  index_key,
13178c2ecf20Sopenharmony_ci				  NULL);
13188c2ecf20Sopenharmony_ci	if (IS_ERR(edit)) {
13198c2ecf20Sopenharmony_ci		ret = PTR_ERR(edit);
13208c2ecf20Sopenharmony_ci		goto error;
13218c2ecf20Sopenharmony_ci	}
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	/* If we're not replacing a link in-place then we're going to need some
13248c2ecf20Sopenharmony_ci	 * extra quota.
13258c2ecf20Sopenharmony_ci	 */
13268c2ecf20Sopenharmony_ci	if (!edit->dead_leaf) {
13278c2ecf20Sopenharmony_ci		ret = key_payload_reserve(keyring,
13288c2ecf20Sopenharmony_ci					  keyring->datalen + KEYQUOTA_LINK_BYTES);
13298c2ecf20Sopenharmony_ci		if (ret < 0)
13308c2ecf20Sopenharmony_ci			goto error_cancel;
13318c2ecf20Sopenharmony_ci	}
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	*_edit = edit;
13348c2ecf20Sopenharmony_ci	kleave(" = 0");
13358c2ecf20Sopenharmony_ci	return 0;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_cierror_cancel:
13388c2ecf20Sopenharmony_ci	assoc_array_cancel_edit(edit);
13398c2ecf20Sopenharmony_cierror:
13408c2ecf20Sopenharmony_ci	kleave(" = %d", ret);
13418c2ecf20Sopenharmony_ci	return ret;
13428c2ecf20Sopenharmony_ci}
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci/*
13458c2ecf20Sopenharmony_ci * Check already instantiated keys aren't going to be a problem.
13468c2ecf20Sopenharmony_ci *
13478c2ecf20Sopenharmony_ci * The caller must have called __key_link_begin(). Don't need to call this for
13488c2ecf20Sopenharmony_ci * keys that were created since __key_link_begin() was called.
13498c2ecf20Sopenharmony_ci */
13508c2ecf20Sopenharmony_ciint __key_link_check_live_key(struct key *keyring, struct key *key)
13518c2ecf20Sopenharmony_ci{
13528c2ecf20Sopenharmony_ci	if (key->type == &key_type_keyring)
13538c2ecf20Sopenharmony_ci		/* check that we aren't going to create a cycle by linking one
13548c2ecf20Sopenharmony_ci		 * keyring to another */
13558c2ecf20Sopenharmony_ci		return keyring_detect_cycle(keyring, key);
13568c2ecf20Sopenharmony_ci	return 0;
13578c2ecf20Sopenharmony_ci}
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci/*
13608c2ecf20Sopenharmony_ci * Link a key into to a keyring.
13618c2ecf20Sopenharmony_ci *
13628c2ecf20Sopenharmony_ci * Must be called with __key_link_begin() having being called.  Discards any
13638c2ecf20Sopenharmony_ci * already extant link to matching key if there is one, so that each keyring
13648c2ecf20Sopenharmony_ci * holds at most one link to any given key of a particular type+description
13658c2ecf20Sopenharmony_ci * combination.
13668c2ecf20Sopenharmony_ci */
13678c2ecf20Sopenharmony_civoid __key_link(struct key *keyring, struct key *key,
13688c2ecf20Sopenharmony_ci		struct assoc_array_edit **_edit)
13698c2ecf20Sopenharmony_ci{
13708c2ecf20Sopenharmony_ci	__key_get(key);
13718c2ecf20Sopenharmony_ci	assoc_array_insert_set_object(*_edit, keyring_key_to_ptr(key));
13728c2ecf20Sopenharmony_ci	assoc_array_apply_edit(*_edit);
13738c2ecf20Sopenharmony_ci	*_edit = NULL;
13748c2ecf20Sopenharmony_ci	notify_key(keyring, NOTIFY_KEY_LINKED, key_serial(key));
13758c2ecf20Sopenharmony_ci}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci/*
13788c2ecf20Sopenharmony_ci * Finish linking a key into to a keyring.
13798c2ecf20Sopenharmony_ci *
13808c2ecf20Sopenharmony_ci * Must be called with __key_link_begin() having being called.
13818c2ecf20Sopenharmony_ci */
13828c2ecf20Sopenharmony_civoid __key_link_end(struct key *keyring,
13838c2ecf20Sopenharmony_ci		    const struct keyring_index_key *index_key,
13848c2ecf20Sopenharmony_ci		    struct assoc_array_edit *edit)
13858c2ecf20Sopenharmony_ci	__releases(&keyring->sem)
13868c2ecf20Sopenharmony_ci	__releases(&keyring_serialise_link_lock)
13878c2ecf20Sopenharmony_ci{
13888c2ecf20Sopenharmony_ci	BUG_ON(index_key->type == NULL);
13898c2ecf20Sopenharmony_ci	kenter("%d,%s,", keyring->serial, index_key->type->name);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (edit) {
13928c2ecf20Sopenharmony_ci		if (!edit->dead_leaf) {
13938c2ecf20Sopenharmony_ci			key_payload_reserve(keyring,
13948c2ecf20Sopenharmony_ci				keyring->datalen - KEYQUOTA_LINK_BYTES);
13958c2ecf20Sopenharmony_ci		}
13968c2ecf20Sopenharmony_ci		assoc_array_cancel_edit(edit);
13978c2ecf20Sopenharmony_ci	}
13988c2ecf20Sopenharmony_ci	up_write(&keyring->sem);
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	if (index_key->type == &key_type_keyring)
14018c2ecf20Sopenharmony_ci		mutex_unlock(&keyring_serialise_link_lock);
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci/*
14058c2ecf20Sopenharmony_ci * Check addition of keys to restricted keyrings.
14068c2ecf20Sopenharmony_ci */
14078c2ecf20Sopenharmony_cistatic int __key_link_check_restriction(struct key *keyring, struct key *key)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	if (!keyring->restrict_link || !keyring->restrict_link->check)
14108c2ecf20Sopenharmony_ci		return 0;
14118c2ecf20Sopenharmony_ci	return keyring->restrict_link->check(keyring, key->type, &key->payload,
14128c2ecf20Sopenharmony_ci					     keyring->restrict_link->key);
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci/**
14168c2ecf20Sopenharmony_ci * key_link - Link a key to a keyring
14178c2ecf20Sopenharmony_ci * @keyring: The keyring to make the link in.
14188c2ecf20Sopenharmony_ci * @key: The key to link to.
14198c2ecf20Sopenharmony_ci *
14208c2ecf20Sopenharmony_ci * Make a link in a keyring to a key, such that the keyring holds a reference
14218c2ecf20Sopenharmony_ci * on that key and the key can potentially be found by searching that keyring.
14228c2ecf20Sopenharmony_ci *
14238c2ecf20Sopenharmony_ci * This function will write-lock the keyring's semaphore and will consume some
14248c2ecf20Sopenharmony_ci * of the user's key data quota to hold the link.
14258c2ecf20Sopenharmony_ci *
14268c2ecf20Sopenharmony_ci * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring,
14278c2ecf20Sopenharmony_ci * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is
14288c2ecf20Sopenharmony_ci * full, -EDQUOT if there is insufficient key data quota remaining to add
14298c2ecf20Sopenharmony_ci * another link or -ENOMEM if there's insufficient memory.
14308c2ecf20Sopenharmony_ci *
14318c2ecf20Sopenharmony_ci * It is assumed that the caller has checked that it is permitted for a link to
14328c2ecf20Sopenharmony_ci * be made (the keyring should have Write permission and the key Link
14338c2ecf20Sopenharmony_ci * permission).
14348c2ecf20Sopenharmony_ci */
14358c2ecf20Sopenharmony_ciint key_link(struct key *keyring, struct key *key)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	struct assoc_array_edit *edit = NULL;
14388c2ecf20Sopenharmony_ci	int ret;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage));
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	key_check(keyring);
14438c2ecf20Sopenharmony_ci	key_check(key);
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	ret = __key_link_lock(keyring, &key->index_key);
14468c2ecf20Sopenharmony_ci	if (ret < 0)
14478c2ecf20Sopenharmony_ci		goto error;
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	ret = __key_link_begin(keyring, &key->index_key, &edit);
14508c2ecf20Sopenharmony_ci	if (ret < 0)
14518c2ecf20Sopenharmony_ci		goto error_end;
14528c2ecf20Sopenharmony_ci
14538c2ecf20Sopenharmony_ci	kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
14548c2ecf20Sopenharmony_ci	ret = __key_link_check_restriction(keyring, key);
14558c2ecf20Sopenharmony_ci	if (ret == 0)
14568c2ecf20Sopenharmony_ci		ret = __key_link_check_live_key(keyring, key);
14578c2ecf20Sopenharmony_ci	if (ret == 0)
14588c2ecf20Sopenharmony_ci		__key_link(keyring, key, &edit);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_cierror_end:
14618c2ecf20Sopenharmony_ci	__key_link_end(keyring, &key->index_key, edit);
14628c2ecf20Sopenharmony_cierror:
14638c2ecf20Sopenharmony_ci	kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage));
14648c2ecf20Sopenharmony_ci	return ret;
14658c2ecf20Sopenharmony_ci}
14668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_link);
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci/*
14698c2ecf20Sopenharmony_ci * Lock a keyring for unlink.
14708c2ecf20Sopenharmony_ci */
14718c2ecf20Sopenharmony_cistatic int __key_unlink_lock(struct key *keyring)
14728c2ecf20Sopenharmony_ci	__acquires(&keyring->sem)
14738c2ecf20Sopenharmony_ci{
14748c2ecf20Sopenharmony_ci	if (keyring->type != &key_type_keyring)
14758c2ecf20Sopenharmony_ci		return -ENOTDIR;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	down_write(&keyring->sem);
14788c2ecf20Sopenharmony_ci	return 0;
14798c2ecf20Sopenharmony_ci}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci/*
14828c2ecf20Sopenharmony_ci * Begin the process of unlinking a key from a keyring.
14838c2ecf20Sopenharmony_ci */
14848c2ecf20Sopenharmony_cistatic int __key_unlink_begin(struct key *keyring, struct key *key,
14858c2ecf20Sopenharmony_ci			      struct assoc_array_edit **_edit)
14868c2ecf20Sopenharmony_ci{
14878c2ecf20Sopenharmony_ci	struct assoc_array_edit *edit;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	BUG_ON(*_edit != NULL);
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_ci	edit = assoc_array_delete(&keyring->keys, &keyring_assoc_array_ops,
14928c2ecf20Sopenharmony_ci				  &key->index_key);
14938c2ecf20Sopenharmony_ci	if (IS_ERR(edit))
14948c2ecf20Sopenharmony_ci		return PTR_ERR(edit);
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	if (!edit)
14978c2ecf20Sopenharmony_ci		return -ENOENT;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	*_edit = edit;
15008c2ecf20Sopenharmony_ci	return 0;
15018c2ecf20Sopenharmony_ci}
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci/*
15048c2ecf20Sopenharmony_ci * Apply an unlink change.
15058c2ecf20Sopenharmony_ci */
15068c2ecf20Sopenharmony_cistatic void __key_unlink(struct key *keyring, struct key *key,
15078c2ecf20Sopenharmony_ci			 struct assoc_array_edit **_edit)
15088c2ecf20Sopenharmony_ci{
15098c2ecf20Sopenharmony_ci	assoc_array_apply_edit(*_edit);
15108c2ecf20Sopenharmony_ci	notify_key(keyring, NOTIFY_KEY_UNLINKED, key_serial(key));
15118c2ecf20Sopenharmony_ci	*_edit = NULL;
15128c2ecf20Sopenharmony_ci	key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES);
15138c2ecf20Sopenharmony_ci}
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci/*
15168c2ecf20Sopenharmony_ci * Finish unlinking a key from to a keyring.
15178c2ecf20Sopenharmony_ci */
15188c2ecf20Sopenharmony_cistatic void __key_unlink_end(struct key *keyring,
15198c2ecf20Sopenharmony_ci			     struct key *key,
15208c2ecf20Sopenharmony_ci			     struct assoc_array_edit *edit)
15218c2ecf20Sopenharmony_ci	__releases(&keyring->sem)
15228c2ecf20Sopenharmony_ci{
15238c2ecf20Sopenharmony_ci	if (edit)
15248c2ecf20Sopenharmony_ci		assoc_array_cancel_edit(edit);
15258c2ecf20Sopenharmony_ci	up_write(&keyring->sem);
15268c2ecf20Sopenharmony_ci}
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci/**
15298c2ecf20Sopenharmony_ci * key_unlink - Unlink the first link to a key from a keyring.
15308c2ecf20Sopenharmony_ci * @keyring: The keyring to remove the link from.
15318c2ecf20Sopenharmony_ci * @key: The key the link is to.
15328c2ecf20Sopenharmony_ci *
15338c2ecf20Sopenharmony_ci * Remove a link from a keyring to a key.
15348c2ecf20Sopenharmony_ci *
15358c2ecf20Sopenharmony_ci * This function will write-lock the keyring's semaphore.
15368c2ecf20Sopenharmony_ci *
15378c2ecf20Sopenharmony_ci * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if
15388c2ecf20Sopenharmony_ci * the key isn't linked to by the keyring or -ENOMEM if there's insufficient
15398c2ecf20Sopenharmony_ci * memory.
15408c2ecf20Sopenharmony_ci *
15418c2ecf20Sopenharmony_ci * It is assumed that the caller has checked that it is permitted for a link to
15428c2ecf20Sopenharmony_ci * be removed (the keyring should have Write permission; no permissions are
15438c2ecf20Sopenharmony_ci * required on the key).
15448c2ecf20Sopenharmony_ci */
15458c2ecf20Sopenharmony_ciint key_unlink(struct key *keyring, struct key *key)
15468c2ecf20Sopenharmony_ci{
15478c2ecf20Sopenharmony_ci	struct assoc_array_edit *edit = NULL;
15488c2ecf20Sopenharmony_ci	int ret;
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	key_check(keyring);
15518c2ecf20Sopenharmony_ci	key_check(key);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	ret = __key_unlink_lock(keyring);
15548c2ecf20Sopenharmony_ci	if (ret < 0)
15558c2ecf20Sopenharmony_ci		return ret;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	ret = __key_unlink_begin(keyring, key, &edit);
15588c2ecf20Sopenharmony_ci	if (ret == 0)
15598c2ecf20Sopenharmony_ci		__key_unlink(keyring, key, &edit);
15608c2ecf20Sopenharmony_ci	__key_unlink_end(keyring, key, edit);
15618c2ecf20Sopenharmony_ci	return ret;
15628c2ecf20Sopenharmony_ci}
15638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_unlink);
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci/**
15668c2ecf20Sopenharmony_ci * key_move - Move a key from one keyring to another
15678c2ecf20Sopenharmony_ci * @key: The key to move
15688c2ecf20Sopenharmony_ci * @from_keyring: The keyring to remove the link from.
15698c2ecf20Sopenharmony_ci * @to_keyring: The keyring to make the link in.
15708c2ecf20Sopenharmony_ci * @flags: Qualifying flags, such as KEYCTL_MOVE_EXCL.
15718c2ecf20Sopenharmony_ci *
15728c2ecf20Sopenharmony_ci * Make a link in @to_keyring to a key, such that the keyring holds a reference
15738c2ecf20Sopenharmony_ci * on that key and the key can potentially be found by searching that keyring
15748c2ecf20Sopenharmony_ci * whilst simultaneously removing a link to the key from @from_keyring.
15758c2ecf20Sopenharmony_ci *
15768c2ecf20Sopenharmony_ci * This function will write-lock both keyring's semaphores and will consume
15778c2ecf20Sopenharmony_ci * some of the user's key data quota to hold the link on @to_keyring.
15788c2ecf20Sopenharmony_ci *
15798c2ecf20Sopenharmony_ci * Returns 0 if successful, -ENOTDIR if either keyring isn't a keyring,
15808c2ecf20Sopenharmony_ci * -EKEYREVOKED if either keyring has been revoked, -ENFILE if the second
15818c2ecf20Sopenharmony_ci * keyring is full, -EDQUOT if there is insufficient key data quota remaining
15828c2ecf20Sopenharmony_ci * to add another link or -ENOMEM if there's insufficient memory.  If
15838c2ecf20Sopenharmony_ci * KEYCTL_MOVE_EXCL is set, then -EEXIST will be returned if there's already a
15848c2ecf20Sopenharmony_ci * matching key in @to_keyring.
15858c2ecf20Sopenharmony_ci *
15868c2ecf20Sopenharmony_ci * It is assumed that the caller has checked that it is permitted for a link to
15878c2ecf20Sopenharmony_ci * be made (the keyring should have Write permission and the key Link
15888c2ecf20Sopenharmony_ci * permission).
15898c2ecf20Sopenharmony_ci */
15908c2ecf20Sopenharmony_ciint key_move(struct key *key,
15918c2ecf20Sopenharmony_ci	     struct key *from_keyring,
15928c2ecf20Sopenharmony_ci	     struct key *to_keyring,
15938c2ecf20Sopenharmony_ci	     unsigned int flags)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct assoc_array_edit *from_edit = NULL, *to_edit = NULL;
15968c2ecf20Sopenharmony_ci	int ret;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	kenter("%d,%d,%d", key->serial, from_keyring->serial, to_keyring->serial);
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci	if (from_keyring == to_keyring)
16018c2ecf20Sopenharmony_ci		return 0;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci	key_check(key);
16048c2ecf20Sopenharmony_ci	key_check(from_keyring);
16058c2ecf20Sopenharmony_ci	key_check(to_keyring);
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	ret = __key_move_lock(from_keyring, to_keyring, &key->index_key);
16088c2ecf20Sopenharmony_ci	if (ret < 0)
16098c2ecf20Sopenharmony_ci		goto out;
16108c2ecf20Sopenharmony_ci	ret = __key_unlink_begin(from_keyring, key, &from_edit);
16118c2ecf20Sopenharmony_ci	if (ret < 0)
16128c2ecf20Sopenharmony_ci		goto error;
16138c2ecf20Sopenharmony_ci	ret = __key_link_begin(to_keyring, &key->index_key, &to_edit);
16148c2ecf20Sopenharmony_ci	if (ret < 0)
16158c2ecf20Sopenharmony_ci		goto error;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	ret = -EEXIST;
16188c2ecf20Sopenharmony_ci	if (to_edit->dead_leaf && (flags & KEYCTL_MOVE_EXCL))
16198c2ecf20Sopenharmony_ci		goto error;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	ret = __key_link_check_restriction(to_keyring, key);
16228c2ecf20Sopenharmony_ci	if (ret < 0)
16238c2ecf20Sopenharmony_ci		goto error;
16248c2ecf20Sopenharmony_ci	ret = __key_link_check_live_key(to_keyring, key);
16258c2ecf20Sopenharmony_ci	if (ret < 0)
16268c2ecf20Sopenharmony_ci		goto error;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	__key_unlink(from_keyring, key, &from_edit);
16298c2ecf20Sopenharmony_ci	__key_link(to_keyring, key, &to_edit);
16308c2ecf20Sopenharmony_cierror:
16318c2ecf20Sopenharmony_ci	__key_link_end(to_keyring, &key->index_key, to_edit);
16328c2ecf20Sopenharmony_ci	__key_unlink_end(from_keyring, key, from_edit);
16338c2ecf20Sopenharmony_ciout:
16348c2ecf20Sopenharmony_ci	kleave(" = %d", ret);
16358c2ecf20Sopenharmony_ci	return ret;
16368c2ecf20Sopenharmony_ci}
16378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(key_move);
16388c2ecf20Sopenharmony_ci
16398c2ecf20Sopenharmony_ci/**
16408c2ecf20Sopenharmony_ci * keyring_clear - Clear a keyring
16418c2ecf20Sopenharmony_ci * @keyring: The keyring to clear.
16428c2ecf20Sopenharmony_ci *
16438c2ecf20Sopenharmony_ci * Clear the contents of the specified keyring.
16448c2ecf20Sopenharmony_ci *
16458c2ecf20Sopenharmony_ci * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring.
16468c2ecf20Sopenharmony_ci */
16478c2ecf20Sopenharmony_ciint keyring_clear(struct key *keyring)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	struct assoc_array_edit *edit;
16508c2ecf20Sopenharmony_ci	int ret;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	if (keyring->type != &key_type_keyring)
16538c2ecf20Sopenharmony_ci		return -ENOTDIR;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	down_write(&keyring->sem);
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	edit = assoc_array_clear(&keyring->keys, &keyring_assoc_array_ops);
16588c2ecf20Sopenharmony_ci	if (IS_ERR(edit)) {
16598c2ecf20Sopenharmony_ci		ret = PTR_ERR(edit);
16608c2ecf20Sopenharmony_ci	} else {
16618c2ecf20Sopenharmony_ci		if (edit)
16628c2ecf20Sopenharmony_ci			assoc_array_apply_edit(edit);
16638c2ecf20Sopenharmony_ci		notify_key(keyring, NOTIFY_KEY_CLEARED, 0);
16648c2ecf20Sopenharmony_ci		key_payload_reserve(keyring, 0);
16658c2ecf20Sopenharmony_ci		ret = 0;
16668c2ecf20Sopenharmony_ci	}
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	up_write(&keyring->sem);
16698c2ecf20Sopenharmony_ci	return ret;
16708c2ecf20Sopenharmony_ci}
16718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(keyring_clear);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci/*
16748c2ecf20Sopenharmony_ci * Dispose of the links from a revoked keyring.
16758c2ecf20Sopenharmony_ci *
16768c2ecf20Sopenharmony_ci * This is called with the key sem write-locked.
16778c2ecf20Sopenharmony_ci */
16788c2ecf20Sopenharmony_cistatic void keyring_revoke(struct key *keyring)
16798c2ecf20Sopenharmony_ci{
16808c2ecf20Sopenharmony_ci	struct assoc_array_edit *edit;
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	edit = assoc_array_clear(&keyring->keys, &keyring_assoc_array_ops);
16838c2ecf20Sopenharmony_ci	if (!IS_ERR(edit)) {
16848c2ecf20Sopenharmony_ci		if (edit)
16858c2ecf20Sopenharmony_ci			assoc_array_apply_edit(edit);
16868c2ecf20Sopenharmony_ci		key_payload_reserve(keyring, 0);
16878c2ecf20Sopenharmony_ci	}
16888c2ecf20Sopenharmony_ci}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_cistatic bool keyring_gc_select_iterator(void *object, void *iterator_data)
16918c2ecf20Sopenharmony_ci{
16928c2ecf20Sopenharmony_ci	struct key *key = keyring_ptr_to_key(object);
16938c2ecf20Sopenharmony_ci	time64_t *limit = iterator_data;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci	if (key_is_dead(key, *limit))
16968c2ecf20Sopenharmony_ci		return false;
16978c2ecf20Sopenharmony_ci	key_get(key);
16988c2ecf20Sopenharmony_ci	return true;
16998c2ecf20Sopenharmony_ci}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_cistatic int keyring_gc_check_iterator(const void *object, void *iterator_data)
17028c2ecf20Sopenharmony_ci{
17038c2ecf20Sopenharmony_ci	const struct key *key = keyring_ptr_to_key(object);
17048c2ecf20Sopenharmony_ci	time64_t *limit = iterator_data;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	key_check(key);
17078c2ecf20Sopenharmony_ci	return key_is_dead(key, *limit);
17088c2ecf20Sopenharmony_ci}
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci/*
17118c2ecf20Sopenharmony_ci * Garbage collect pointers from a keyring.
17128c2ecf20Sopenharmony_ci *
17138c2ecf20Sopenharmony_ci * Not called with any locks held.  The keyring's key struct will not be
17148c2ecf20Sopenharmony_ci * deallocated under us as only our caller may deallocate it.
17158c2ecf20Sopenharmony_ci */
17168c2ecf20Sopenharmony_civoid keyring_gc(struct key *keyring, time64_t limit)
17178c2ecf20Sopenharmony_ci{
17188c2ecf20Sopenharmony_ci	int result;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	kenter("%x{%s}", keyring->serial, keyring->description ?: "");
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) |
17238c2ecf20Sopenharmony_ci			      (1 << KEY_FLAG_REVOKED)))
17248c2ecf20Sopenharmony_ci		goto dont_gc;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	/* scan the keyring looking for dead keys */
17278c2ecf20Sopenharmony_ci	rcu_read_lock();
17288c2ecf20Sopenharmony_ci	result = assoc_array_iterate(&keyring->keys,
17298c2ecf20Sopenharmony_ci				     keyring_gc_check_iterator, &limit);
17308c2ecf20Sopenharmony_ci	rcu_read_unlock();
17318c2ecf20Sopenharmony_ci	if (result == true)
17328c2ecf20Sopenharmony_ci		goto do_gc;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_cidont_gc:
17358c2ecf20Sopenharmony_ci	kleave(" [no gc]");
17368c2ecf20Sopenharmony_ci	return;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_cido_gc:
17398c2ecf20Sopenharmony_ci	down_write(&keyring->sem);
17408c2ecf20Sopenharmony_ci	assoc_array_gc(&keyring->keys, &keyring_assoc_array_ops,
17418c2ecf20Sopenharmony_ci		       keyring_gc_select_iterator, &limit);
17428c2ecf20Sopenharmony_ci	up_write(&keyring->sem);
17438c2ecf20Sopenharmony_ci	kleave(" [gc]");
17448c2ecf20Sopenharmony_ci}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci/*
17478c2ecf20Sopenharmony_ci * Garbage collect restriction pointers from a keyring.
17488c2ecf20Sopenharmony_ci *
17498c2ecf20Sopenharmony_ci * Keyring restrictions are associated with a key type, and must be cleaned
17508c2ecf20Sopenharmony_ci * up if the key type is unregistered. The restriction is altered to always
17518c2ecf20Sopenharmony_ci * reject additional keys so a keyring cannot be opened up by unregistering
17528c2ecf20Sopenharmony_ci * a key type.
17538c2ecf20Sopenharmony_ci *
17548c2ecf20Sopenharmony_ci * Not called with any keyring locks held. The keyring's key struct will not
17558c2ecf20Sopenharmony_ci * be deallocated under us as only our caller may deallocate it.
17568c2ecf20Sopenharmony_ci *
17578c2ecf20Sopenharmony_ci * The caller is required to hold key_types_sem and dead_type->sem. This is
17588c2ecf20Sopenharmony_ci * fulfilled by key_gc_keytype() holding the locks on behalf of
17598c2ecf20Sopenharmony_ci * key_garbage_collector(), which it invokes on a workqueue.
17608c2ecf20Sopenharmony_ci */
17618c2ecf20Sopenharmony_civoid keyring_restriction_gc(struct key *keyring, struct key_type *dead_type)
17628c2ecf20Sopenharmony_ci{
17638c2ecf20Sopenharmony_ci	struct key_restriction *keyres;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	kenter("%x{%s}", keyring->serial, keyring->description ?: "");
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	/*
17688c2ecf20Sopenharmony_ci	 * keyring->restrict_link is only assigned at key allocation time
17698c2ecf20Sopenharmony_ci	 * or with the key type locked, so the only values that could be
17708c2ecf20Sopenharmony_ci	 * concurrently assigned to keyring->restrict_link are for key
17718c2ecf20Sopenharmony_ci	 * types other than dead_type. Given this, it's ok to check
17728c2ecf20Sopenharmony_ci	 * the key type before acquiring keyring->sem.
17738c2ecf20Sopenharmony_ci	 */
17748c2ecf20Sopenharmony_ci	if (!dead_type || !keyring->restrict_link ||
17758c2ecf20Sopenharmony_ci	    keyring->restrict_link->keytype != dead_type) {
17768c2ecf20Sopenharmony_ci		kleave(" [no restriction gc]");
17778c2ecf20Sopenharmony_ci		return;
17788c2ecf20Sopenharmony_ci	}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	/* Lock the keyring to ensure that a link is not in progress */
17818c2ecf20Sopenharmony_ci	down_write(&keyring->sem);
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	keyres = keyring->restrict_link;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	keyres->check = restrict_link_reject;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	key_put(keyres->key);
17888c2ecf20Sopenharmony_ci	keyres->key = NULL;
17898c2ecf20Sopenharmony_ci	keyres->keytype = NULL;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	up_write(&keyring->sem);
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	kleave(" [restriction gc]");
17948c2ecf20Sopenharmony_ci}
1795