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