169664cf1SDavid Howells /* Keyring handling 21da177e4SLinus Torvalds * 369664cf1SDavid Howells * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 1629db9190SDavid Howells #include <linux/security.h> 171da177e4SLinus Torvalds #include <linux/seq_file.h> 181da177e4SLinus Torvalds #include <linux/err.h> 19e9e349b0SDavid Howells #include <keys/keyring-type.h> 20512ea3bcSChihau Chau #include <linux/uaccess.h> 211da177e4SLinus Torvalds #include "internal.h" 221da177e4SLinus Torvalds 23f0641cbaSDavid Howells #define rcu_dereference_locked_keyring(keyring) \ 24f0641cbaSDavid Howells (rcu_dereference_protected( \ 25f0641cbaSDavid Howells (keyring)->payload.subscriptions, \ 26f0641cbaSDavid Howells rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) 27f0641cbaSDavid Howells 28233e4735SDavid Howells #define rcu_deref_link_locked(klist, index, keyring) \ 29233e4735SDavid Howells (rcu_dereference_protected( \ 30233e4735SDavid Howells (klist)->keys[index], \ 31233e4735SDavid Howells rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) 32233e4735SDavid Howells 3331d5a79dSDavid Howells #define MAX_KEYRING_LINKS \ 3431d5a79dSDavid Howells min_t(size_t, USHRT_MAX - 1, \ 3531d5a79dSDavid Howells ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) 3631d5a79dSDavid Howells 37ceb73c12SDavid Howells #define KEY_LINK_FIXQUOTA 1UL 38ceb73c12SDavid Howells 391da177e4SLinus Torvalds /* 40973c9f4fSDavid Howells * When plumbing the depths of the key tree, this sets a hard limit 41973c9f4fSDavid Howells * set on how deep we're willing to go. 421da177e4SLinus Torvalds */ 431da177e4SLinus Torvalds #define KEYRING_SEARCH_MAX_DEPTH 6 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds /* 46973c9f4fSDavid Howells * We keep all named keyrings in a hash to speed looking them up. 471da177e4SLinus Torvalds */ 481da177e4SLinus Torvalds #define KEYRING_NAME_HASH_SIZE (1 << 5) 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; 511da177e4SLinus Torvalds static DEFINE_RWLOCK(keyring_name_lock); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds static inline unsigned keyring_hash(const char *desc) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds unsigned bucket = 0; 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds for (; *desc; desc++) 581da177e4SLinus Torvalds bucket += (unsigned char)*desc; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds return bucket & (KEYRING_NAME_HASH_SIZE - 1); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 64973c9f4fSDavid Howells * The keyring key type definition. Keyrings are simply keys of this type and 65973c9f4fSDavid Howells * can be treated as ordinary keys in addition to having their own special 66973c9f4fSDavid Howells * operations. 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 69cf7f601cSDavid Howells struct key_preparsed_payload *prep); 701da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *criterion); 7131204ed9SDavid Howells static void keyring_revoke(struct key *keyring); 721da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring); 731da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m); 741da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 751da177e4SLinus Torvalds char __user *buffer, size_t buflen); 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds struct key_type key_type_keyring = { 781da177e4SLinus Torvalds .name = "keyring", 791da177e4SLinus Torvalds .def_datalen = sizeof(struct keyring_list), 801da177e4SLinus Torvalds .instantiate = keyring_instantiate, 811da177e4SLinus Torvalds .match = keyring_match, 8231204ed9SDavid Howells .revoke = keyring_revoke, 831da177e4SLinus Torvalds .destroy = keyring_destroy, 841da177e4SLinus Torvalds .describe = keyring_describe, 851da177e4SLinus Torvalds .read = keyring_read, 861da177e4SLinus Torvalds }; 877318226eSDavid Howells EXPORT_SYMBOL(key_type_keyring); 887318226eSDavid Howells 891da177e4SLinus Torvalds /* 90973c9f4fSDavid Howells * Semaphore to serialise link/link calls to prevent two link calls in parallel 91973c9f4fSDavid Howells * introducing a cycle. 921da177e4SLinus Torvalds */ 931ae8f407SAdrian Bunk static DECLARE_RWSEM(keyring_serialise_link_sem); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* 96973c9f4fSDavid Howells * Publish the name of a keyring so that it can be found by name (if it has 97973c9f4fSDavid Howells * one). 981da177e4SLinus Torvalds */ 9969664cf1SDavid Howells static void keyring_publish_name(struct key *keyring) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds int bucket; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds if (keyring->description) { 1041da177e4SLinus Torvalds bucket = keyring_hash(keyring->description); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds write_lock(&keyring_name_lock); 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds if (!keyring_name_hash[bucket].next) 1091da177e4SLinus Torvalds INIT_LIST_HEAD(&keyring_name_hash[bucket]); 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds list_add_tail(&keyring->type_data.link, 1121da177e4SLinus Torvalds &keyring_name_hash[bucket]); 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 1151da177e4SLinus Torvalds } 116a8b17ed0SDavid Howells } 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* 119973c9f4fSDavid Howells * Initialise a keyring. 120973c9f4fSDavid Howells * 121973c9f4fSDavid Howells * Returns 0 on success, -EINVAL if given any data. 1221da177e4SLinus Torvalds */ 1231da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 124cf7f601cSDavid Howells struct key_preparsed_payload *prep) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds int ret; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds ret = -EINVAL; 129cf7f601cSDavid Howells if (prep->datalen == 0) { 1301da177e4SLinus Torvalds /* make the keyring available by name if it has one */ 1311da177e4SLinus Torvalds keyring_publish_name(keyring); 1321da177e4SLinus Torvalds ret = 0; 1331da177e4SLinus Torvalds } 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds return ret; 136a8b17ed0SDavid Howells } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* 139973c9f4fSDavid Howells * Match keyrings on their name 1401da177e4SLinus Torvalds */ 1411da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *description) 1421da177e4SLinus Torvalds { 1431da177e4SLinus Torvalds return keyring->description && 1441da177e4SLinus Torvalds strcmp(keyring->description, description) == 0; 145a8b17ed0SDavid Howells } 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds /* 148973c9f4fSDavid Howells * Clean up a keyring when it is destroyed. Unpublish its name if it had one 149973c9f4fSDavid Howells * and dispose of its data. 150233e4735SDavid Howells * 151233e4735SDavid Howells * The garbage collector detects the final key_put(), removes the keyring from 152233e4735SDavid Howells * the serial number tree and then does RCU synchronisation before coming here, 153233e4735SDavid Howells * so we shouldn't need to worry about code poking around here with the RCU 154233e4735SDavid Howells * readlock held by this time. 1551da177e4SLinus Torvalds */ 1561da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring) 1571da177e4SLinus Torvalds { 1581da177e4SLinus Torvalds struct keyring_list *klist; 1591da177e4SLinus Torvalds int loop; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds if (keyring->description) { 1621da177e4SLinus Torvalds write_lock(&keyring_name_lock); 16394efe72fSDavid Howells 16494efe72fSDavid Howells if (keyring->type_data.link.next != NULL && 16594efe72fSDavid Howells !list_empty(&keyring->type_data.link)) 1661da177e4SLinus Torvalds list_del(&keyring->type_data.link); 16794efe72fSDavid Howells 1681da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 171233e4735SDavid Howells klist = rcu_access_pointer(keyring->payload.subscriptions); 1721da177e4SLinus Torvalds if (klist) { 1731da177e4SLinus Torvalds for (loop = klist->nkeys - 1; loop >= 0; loop--) 174233e4735SDavid Howells key_put(rcu_access_pointer(klist->keys[loop])); 1751da177e4SLinus Torvalds kfree(klist); 1761da177e4SLinus Torvalds } 177a8b17ed0SDavid Howells } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /* 180973c9f4fSDavid Howells * Describe a keyring for /proc. 1811da177e4SLinus Torvalds */ 1821da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds struct keyring_list *klist; 1851da177e4SLinus Torvalds 186c8563473Swzt.wzt@gmail.com if (keyring->description) 1871da177e4SLinus Torvalds seq_puts(m, keyring->description); 188c8563473Swzt.wzt@gmail.com else 1891da177e4SLinus Torvalds seq_puts(m, "[anon]"); 1901da177e4SLinus Torvalds 19178b7280cSDavid Howells if (key_is_instantiated(keyring)) { 19276d8aeabSDavid Howells rcu_read_lock(); 19376d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 1941da177e4SLinus Torvalds if (klist) 1951da177e4SLinus Torvalds seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); 1961da177e4SLinus Torvalds else 1971da177e4SLinus Torvalds seq_puts(m, ": empty"); 19876d8aeabSDavid Howells rcu_read_unlock(); 199a8b17ed0SDavid Howells } 20078b7280cSDavid Howells } 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds /* 203973c9f4fSDavid Howells * Read a list of key IDs from the keyring's contents in binary form 204973c9f4fSDavid Howells * 205973c9f4fSDavid Howells * The keyring's semaphore is read-locked by the caller. 2061da177e4SLinus Torvalds */ 2071da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 2081da177e4SLinus Torvalds char __user *buffer, size_t buflen) 2091da177e4SLinus Torvalds { 2101da177e4SLinus Torvalds struct keyring_list *klist; 2111da177e4SLinus Torvalds struct key *key; 2121da177e4SLinus Torvalds size_t qty, tmp; 2131da177e4SLinus Torvalds int loop, ret; 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds ret = 0; 216f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 2171da177e4SLinus Torvalds if (klist) { 2181da177e4SLinus Torvalds /* calculate how much data we could return */ 2191da177e4SLinus Torvalds qty = klist->nkeys * sizeof(key_serial_t); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds if (buffer && buflen > 0) { 2221da177e4SLinus Torvalds if (buflen > qty) 2231da177e4SLinus Torvalds buflen = qty; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds /* copy the IDs of the subscribed keys into the 2261da177e4SLinus Torvalds * buffer */ 2271da177e4SLinus Torvalds ret = -EFAULT; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 230233e4735SDavid Howells key = rcu_deref_link_locked(klist, loop, 231233e4735SDavid Howells keyring); 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds tmp = sizeof(key_serial_t); 2341da177e4SLinus Torvalds if (tmp > buflen) 2351da177e4SLinus Torvalds tmp = buflen; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds if (copy_to_user(buffer, 2381da177e4SLinus Torvalds &key->serial, 2391da177e4SLinus Torvalds tmp) != 0) 2401da177e4SLinus Torvalds goto error; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds buflen -= tmp; 2431da177e4SLinus Torvalds if (buflen == 0) 2441da177e4SLinus Torvalds break; 2451da177e4SLinus Torvalds buffer += tmp; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds ret = qty; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds error: 2531da177e4SLinus Torvalds return ret; 254a8b17ed0SDavid Howells } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /* 257973c9f4fSDavid Howells * Allocate a keyring and link into the destination keyring. 2581da177e4SLinus Torvalds */ 2599a56c2dbSEric W. Biederman struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, 26096b5c8feSDavid Howells const struct cred *cred, key_perm_t perm, 26196b5c8feSDavid Howells unsigned long flags, struct key *dest) 2621da177e4SLinus Torvalds { 2631da177e4SLinus Torvalds struct key *keyring; 2641da177e4SLinus Torvalds int ret; 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds keyring = key_alloc(&key_type_keyring, description, 26796b5c8feSDavid Howells uid, gid, cred, perm, flags); 2681da177e4SLinus Torvalds if (!IS_ERR(keyring)) { 2693e30148cSDavid Howells ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); 2701da177e4SLinus Torvalds if (ret < 0) { 2711da177e4SLinus Torvalds key_put(keyring); 2721da177e4SLinus Torvalds keyring = ERR_PTR(ret); 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds return keyring; 277a8b17ed0SDavid Howells } 278f8aa23a5SDavid Howells EXPORT_SYMBOL(keyring_alloc); 2791da177e4SLinus Torvalds 280973c9f4fSDavid Howells /** 281973c9f4fSDavid Howells * keyring_search_aux - Search a keyring tree for a key matching some criteria 282973c9f4fSDavid Howells * @keyring_ref: A pointer to the keyring with possession indicator. 283973c9f4fSDavid Howells * @cred: The credentials to use for permissions checks. 284973c9f4fSDavid Howells * @type: The type of key to search for. 285973c9f4fSDavid Howells * @description: Parameter for @match. 286973c9f4fSDavid Howells * @match: Function to rule on whether or not a key is the one required. 28778b7280cSDavid Howells * @no_state_check: Don't check if a matching key is bad 288973c9f4fSDavid Howells * 289973c9f4fSDavid Howells * Search the supplied keyring tree for a key that matches the criteria given. 290973c9f4fSDavid Howells * The root keyring and any linked keyrings must grant Search permission to the 291973c9f4fSDavid Howells * caller to be searchable and keys can only be found if they too grant Search 292973c9f4fSDavid Howells * to the caller. The possession flag on the root keyring pointer controls use 293973c9f4fSDavid Howells * of the possessor bits in permissions checking of the entire tree. In 294973c9f4fSDavid Howells * addition, the LSM gets to forbid keyring searches and key matches. 295973c9f4fSDavid Howells * 296973c9f4fSDavid Howells * The search is performed as a breadth-then-depth search up to the prescribed 297973c9f4fSDavid Howells * limit (KEYRING_SEARCH_MAX_DEPTH). 298973c9f4fSDavid Howells * 299973c9f4fSDavid Howells * Keys are matched to the type provided and are then filtered by the match 300973c9f4fSDavid Howells * function, which is given the description to use in any way it sees fit. The 301973c9f4fSDavid Howells * match function may use any attributes of a key that it wishes to to 302973c9f4fSDavid Howells * determine the match. Normally the match function from the key type would be 303973c9f4fSDavid Howells * used. 304973c9f4fSDavid Howells * 305973c9f4fSDavid Howells * RCU is used to prevent the keyring key lists from disappearing without the 306973c9f4fSDavid Howells * need to take lots of locks. 307973c9f4fSDavid Howells * 308973c9f4fSDavid Howells * Returns a pointer to the found key and increments the key usage count if 309973c9f4fSDavid Howells * successful; -EAGAIN if no matching keys were found, or if expired or revoked 310973c9f4fSDavid Howells * keys were found; -ENOKEY if only negative keys were found; -ENOTDIR if the 311973c9f4fSDavid Howells * specified keyring wasn't a keyring. 312973c9f4fSDavid Howells * 313973c9f4fSDavid Howells * In the case of a successful return, the possession attribute from 314973c9f4fSDavid Howells * @keyring_ref is propagated to the returned key reference. 3151da177e4SLinus Torvalds */ 316664cceb0SDavid Howells key_ref_t keyring_search_aux(key_ref_t keyring_ref, 317d84f4f99SDavid Howells const struct cred *cred, 3181da177e4SLinus Torvalds struct key_type *type, 3191da177e4SLinus Torvalds const void *description, 32078b7280cSDavid Howells key_match_func_t match, 32178b7280cSDavid Howells bool no_state_check) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds struct { 32431d5a79dSDavid Howells /* Need a separate keylist pointer for RCU purposes */ 32531d5a79dSDavid Howells struct key *keyring; 32676d8aeabSDavid Howells struct keyring_list *keylist; 3271da177e4SLinus Torvalds int kix; 3281da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds struct keyring_list *keylist; 3311da177e4SLinus Torvalds struct timespec now; 332a5b4bd28SDavid Howells unsigned long kflags; 333664cceb0SDavid Howells struct key *keyring, *key; 334664cceb0SDavid Howells key_ref_t key_ref; 335a5b4bd28SDavid Howells bool possessed; 3361da177e4SLinus Torvalds long err; 337efde8b6eSDavid Howells int sp, nkeys, kix; 3381da177e4SLinus Torvalds 339664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 340664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 3411da177e4SLinus Torvalds key_check(keyring); 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds /* top keyring must have search permission to begin the search */ 344d84f4f99SDavid Howells err = key_task_permission(keyring_ref, cred, KEY_SEARCH); 34529db9190SDavid Howells if (err < 0) { 34629db9190SDavid Howells key_ref = ERR_PTR(err); 3471da177e4SLinus Torvalds goto error; 34829db9190SDavid Howells } 3491da177e4SLinus Torvalds 350664cceb0SDavid Howells key_ref = ERR_PTR(-ENOTDIR); 3511da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 3521da177e4SLinus Torvalds goto error; 3531da177e4SLinus Torvalds 354664cceb0SDavid Howells rcu_read_lock(); 355664cceb0SDavid Howells 3561da177e4SLinus Torvalds now = current_kernel_time(); 3571da177e4SLinus Torvalds err = -EAGAIN; 3581da177e4SLinus Torvalds sp = 0; 3591da177e4SLinus Torvalds 360dceba994SKevin Coffman /* firstly we should check to see if this top-level keyring is what we 361dceba994SKevin Coffman * are looking for */ 362dceba994SKevin Coffman key_ref = ERR_PTR(-EAGAIN); 363dceba994SKevin Coffman kflags = keyring->flags; 364dceba994SKevin Coffman if (keyring->type == type && match(keyring, description)) { 365dceba994SKevin Coffman key = keyring; 36678b7280cSDavid Howells if (no_state_check) 36778b7280cSDavid Howells goto found; 368dceba994SKevin Coffman 369dceba994SKevin Coffman /* check it isn't negative and hasn't expired or been 370dceba994SKevin Coffman * revoked */ 371dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_REVOKED)) 372dceba994SKevin Coffman goto error_2; 373dceba994SKevin Coffman if (key->expiry && now.tv_sec >= key->expiry) 374dceba994SKevin Coffman goto error_2; 375fdd1b945SDavid Howells key_ref = ERR_PTR(key->type_data.reject_error); 376dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_NEGATIVE)) 377dceba994SKevin Coffman goto error_2; 378dceba994SKevin Coffman goto found; 379dceba994SKevin Coffman } 380dceba994SKevin Coffman 381dceba994SKevin Coffman /* otherwise, the top keyring must not be revoked, expired, or 382dceba994SKevin Coffman * negatively instantiated if we are to search it */ 383dceba994SKevin Coffman key_ref = ERR_PTR(-EAGAIN); 384fd75815fSDavid Howells if (kflags & ((1 << KEY_FLAG_INVALIDATED) | 385fd75815fSDavid Howells (1 << KEY_FLAG_REVOKED) | 386fd75815fSDavid Howells (1 << KEY_FLAG_NEGATIVE)) || 387dceba994SKevin Coffman (keyring->expiry && now.tv_sec >= keyring->expiry)) 388dceba994SKevin Coffman goto error_2; 389dceba994SKevin Coffman 3901da177e4SLinus Torvalds /* start processing a new keyring */ 3911da177e4SLinus Torvalds descend: 392fd75815fSDavid Howells kflags = keyring->flags; 393fd75815fSDavid Howells if (kflags & ((1 << KEY_FLAG_INVALIDATED) | 394fd75815fSDavid Howells (1 << KEY_FLAG_REVOKED))) 3951da177e4SLinus Torvalds goto not_this_keyring; 3961da177e4SLinus Torvalds 39776d8aeabSDavid Howells keylist = rcu_dereference(keyring->payload.subscriptions); 3981da177e4SLinus Torvalds if (!keylist) 3991da177e4SLinus Torvalds goto not_this_keyring; 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds /* iterate through the keys in this keyring first */ 402efde8b6eSDavid Howells nkeys = keylist->nkeys; 403efde8b6eSDavid Howells smp_rmb(); 404efde8b6eSDavid Howells for (kix = 0; kix < nkeys; kix++) { 405233e4735SDavid Howells key = rcu_dereference(keylist->keys[kix]); 406dceba994SKevin Coffman kflags = key->flags; 4071da177e4SLinus Torvalds 4081da177e4SLinus Torvalds /* ignore keys not of this type */ 4091da177e4SLinus Torvalds if (key->type != type) 4101da177e4SLinus Torvalds continue; 4111da177e4SLinus Torvalds 412fd75815fSDavid Howells /* skip invalidated, revoked and expired keys */ 41378b7280cSDavid Howells if (!no_state_check) { 414fd75815fSDavid Howells if (kflags & ((1 << KEY_FLAG_INVALIDATED) | 415fd75815fSDavid Howells (1 << KEY_FLAG_REVOKED))) 4161da177e4SLinus Torvalds continue; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds if (key->expiry && now.tv_sec >= key->expiry) 4191da177e4SLinus Torvalds continue; 42078b7280cSDavid Howells } 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds /* keys that don't match */ 4231da177e4SLinus Torvalds if (!match(key, description)) 4241da177e4SLinus Torvalds continue; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /* key must have search permissions */ 42729db9190SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 428d84f4f99SDavid Howells cred, KEY_SEARCH) < 0) 4291da177e4SLinus Torvalds continue; 4301da177e4SLinus Torvalds 43178b7280cSDavid Howells if (no_state_check) 43278b7280cSDavid Howells goto found; 43378b7280cSDavid Howells 434dceba994SKevin Coffman /* we set a different error code if we pass a negative key */ 435dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_NEGATIVE)) { 436fdd1b945SDavid Howells err = key->type_data.reject_error; 4371da177e4SLinus Torvalds continue; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds goto found; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds 4431da177e4SLinus Torvalds /* search through the keyrings nested in this one */ 4441da177e4SLinus Torvalds kix = 0; 4451da177e4SLinus Torvalds ascend: 446efde8b6eSDavid Howells nkeys = keylist->nkeys; 447efde8b6eSDavid Howells smp_rmb(); 448efde8b6eSDavid Howells for (; kix < nkeys; kix++) { 449233e4735SDavid Howells key = rcu_dereference(keylist->keys[kix]); 4501da177e4SLinus Torvalds if (key->type != &key_type_keyring) 45176d8aeabSDavid Howells continue; 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds /* recursively search nested keyrings 4541da177e4SLinus Torvalds * - only search keyrings for which we have search permission 4551da177e4SLinus Torvalds */ 4561da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 45776d8aeabSDavid Howells continue; 4581da177e4SLinus Torvalds 4590f6ed7c2SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 460d84f4f99SDavid Howells cred, KEY_SEARCH) < 0) 46176d8aeabSDavid Howells continue; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds /* stack the current position */ 46431d5a79dSDavid Howells stack[sp].keyring = keyring; 46576d8aeabSDavid Howells stack[sp].keylist = keylist; 4661da177e4SLinus Torvalds stack[sp].kix = kix; 4671da177e4SLinus Torvalds sp++; 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds /* begin again with the new keyring */ 4701da177e4SLinus Torvalds keyring = key; 4711da177e4SLinus Torvalds goto descend; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 4751da177e4SLinus Torvalds * matching key */ 4761da177e4SLinus Torvalds not_this_keyring: 4771da177e4SLinus Torvalds if (sp > 0) { 4781da177e4SLinus Torvalds /* resume the processing of a keyring higher up in the tree */ 4791da177e4SLinus Torvalds sp--; 48031d5a79dSDavid Howells keyring = stack[sp].keyring; 48176d8aeabSDavid Howells keylist = stack[sp].keylist; 4821da177e4SLinus Torvalds kix = stack[sp].kix + 1; 4831da177e4SLinus Torvalds goto ascend; 4841da177e4SLinus Torvalds } 4851da177e4SLinus Torvalds 486664cceb0SDavid Howells key_ref = ERR_PTR(err); 487664cceb0SDavid Howells goto error_2; 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds /* we found a viable match */ 4901da177e4SLinus Torvalds found: 4911da177e4SLinus Torvalds atomic_inc(&key->usage); 49231d5a79dSDavid Howells key->last_used_at = now.tv_sec; 49331d5a79dSDavid Howells keyring->last_used_at = now.tv_sec; 49431d5a79dSDavid Howells while (sp > 0) 49531d5a79dSDavid Howells stack[--sp].keyring->last_used_at = now.tv_sec; 4961da177e4SLinus Torvalds key_check(key); 497664cceb0SDavid Howells key_ref = make_key_ref(key, possessed); 498664cceb0SDavid Howells error_2: 49976d8aeabSDavid Howells rcu_read_unlock(); 500664cceb0SDavid Howells error: 501664cceb0SDavid Howells return key_ref; 502a8b17ed0SDavid Howells } 5031da177e4SLinus Torvalds 504973c9f4fSDavid Howells /** 505973c9f4fSDavid Howells * keyring_search - Search the supplied keyring tree for a matching key 506973c9f4fSDavid Howells * @keyring: The root of the keyring tree to be searched. 507973c9f4fSDavid Howells * @type: The type of keyring we want to find. 508973c9f4fSDavid Howells * @description: The name of the keyring we want to find. 509973c9f4fSDavid Howells * 510973c9f4fSDavid Howells * As keyring_search_aux() above, but using the current task's credentials and 511973c9f4fSDavid Howells * type's default matching function. 5121da177e4SLinus Torvalds */ 513664cceb0SDavid Howells key_ref_t keyring_search(key_ref_t keyring, 5141da177e4SLinus Torvalds struct key_type *type, 5151da177e4SLinus Torvalds const char *description) 5161da177e4SLinus Torvalds { 5173e30148cSDavid Howells if (!type->match) 5183e30148cSDavid Howells return ERR_PTR(-ENOKEY); 5193e30148cSDavid Howells 520d84f4f99SDavid Howells return keyring_search_aux(keyring, current->cred, 52178b7280cSDavid Howells type, description, type->match, false); 522a8b17ed0SDavid Howells } 5231da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_search); 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds /* 526973c9f4fSDavid Howells * Search the given keyring only (no recursion). 527973c9f4fSDavid Howells * 528973c9f4fSDavid Howells * The caller must guarantee that the keyring is a keyring and that the 529973c9f4fSDavid Howells * permission is granted to search the keyring as no check is made here. 530973c9f4fSDavid Howells * 531973c9f4fSDavid Howells * RCU is used to make it unnecessary to lock the keyring key list here. 532973c9f4fSDavid Howells * 533973c9f4fSDavid Howells * Returns a pointer to the found key with usage count incremented if 534973c9f4fSDavid Howells * successful and returns -ENOKEY if not found. Revoked keys and keys not 535973c9f4fSDavid Howells * providing the requested permission are skipped over. 536973c9f4fSDavid Howells * 537973c9f4fSDavid Howells * If successful, the possession indicator is propagated from the keyring ref 538973c9f4fSDavid Howells * to the returned key reference. 5391da177e4SLinus Torvalds */ 540664cceb0SDavid Howells key_ref_t __keyring_search_one(key_ref_t keyring_ref, 541*16feef43SDavid Howells const struct keyring_index_key *index_key, 5421da177e4SLinus Torvalds key_perm_t perm) 5431da177e4SLinus Torvalds { 5441da177e4SLinus Torvalds struct keyring_list *klist; 545664cceb0SDavid Howells struct key *keyring, *key; 546a5b4bd28SDavid Howells bool possessed; 547efde8b6eSDavid Howells int nkeys, loop; 5481da177e4SLinus Torvalds 549664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 550664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 551664cceb0SDavid Howells 55276d8aeabSDavid Howells rcu_read_lock(); 55376d8aeabSDavid Howells 55476d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 5551da177e4SLinus Torvalds if (klist) { 556efde8b6eSDavid Howells nkeys = klist->nkeys; 557efde8b6eSDavid Howells smp_rmb(); 558efde8b6eSDavid Howells for (loop = 0; loop < nkeys ; loop++) { 559233e4735SDavid Howells key = rcu_dereference(klist->keys[loop]); 560*16feef43SDavid Howells if (key->type == index_key->type && 5613e30148cSDavid Howells (!key->type->match || 562*16feef43SDavid Howells key->type->match(key, index_key->description)) && 563664cceb0SDavid Howells key_permission(make_key_ref(key, possessed), 564db1d1d57SDavid Howells perm) == 0 && 565fd75815fSDavid Howells !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | 566fd75815fSDavid Howells (1 << KEY_FLAG_REVOKED))) 5671da177e4SLinus Torvalds ) 5681da177e4SLinus Torvalds goto found; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 572664cceb0SDavid Howells rcu_read_unlock(); 573664cceb0SDavid Howells return ERR_PTR(-ENOKEY); 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds found: 5761da177e4SLinus Torvalds atomic_inc(&key->usage); 57731d5a79dSDavid Howells keyring->last_used_at = key->last_used_at = 57831d5a79dSDavid Howells current_kernel_time().tv_sec; 57976d8aeabSDavid Howells rcu_read_unlock(); 580664cceb0SDavid Howells return make_key_ref(key, possessed); 581a8b17ed0SDavid Howells } 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds /* 584973c9f4fSDavid Howells * Find a keyring with the specified name. 585973c9f4fSDavid Howells * 586973c9f4fSDavid Howells * All named keyrings in the current user namespace are searched, provided they 587973c9f4fSDavid Howells * grant Search permission directly to the caller (unless this check is 588973c9f4fSDavid Howells * skipped). Keyrings whose usage points have reached zero or who have been 589973c9f4fSDavid Howells * revoked are skipped. 590973c9f4fSDavid Howells * 591973c9f4fSDavid Howells * Returns a pointer to the keyring with the keyring's refcount having being 592973c9f4fSDavid Howells * incremented on success. -ENOKEY is returned if a key could not be found. 5931da177e4SLinus Torvalds */ 59469664cf1SDavid Howells struct key *find_keyring_by_name(const char *name, bool skip_perm_check) 5951da177e4SLinus Torvalds { 5961da177e4SLinus Torvalds struct key *keyring; 5971da177e4SLinus Torvalds int bucket; 5981da177e4SLinus Torvalds 5991da177e4SLinus Torvalds if (!name) 600cea7daa3SToshiyuki Okajima return ERR_PTR(-EINVAL); 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds bucket = keyring_hash(name); 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds read_lock(&keyring_name_lock); 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds if (keyring_name_hash[bucket].next) { 6071da177e4SLinus Torvalds /* search this hash bucket for a keyring with a matching name 6081da177e4SLinus Torvalds * that's readable and that hasn't been revoked */ 6091da177e4SLinus Torvalds list_for_each_entry(keyring, 6101da177e4SLinus Torvalds &keyring_name_hash[bucket], 6111da177e4SLinus Torvalds type_data.link 6121da177e4SLinus Torvalds ) { 6139a56c2dbSEric W. Biederman if (!kuid_has_mapping(current_user_ns(), keyring->user->uid)) 6142ea190d0SSerge E. Hallyn continue; 6152ea190d0SSerge E. Hallyn 61676d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 6171da177e4SLinus Torvalds continue; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds if (strcmp(keyring->description, name) != 0) 6201da177e4SLinus Torvalds continue; 6211da177e4SLinus Torvalds 62269664cf1SDavid Howells if (!skip_perm_check && 62369664cf1SDavid Howells key_permission(make_key_ref(keyring, 0), 62429db9190SDavid Howells KEY_SEARCH) < 0) 6251da177e4SLinus Torvalds continue; 6261da177e4SLinus Torvalds 627cea7daa3SToshiyuki Okajima /* we've got a match but we might end up racing with 628cea7daa3SToshiyuki Okajima * key_cleanup() if the keyring is currently 'dead' 629cea7daa3SToshiyuki Okajima * (ie. it has a zero usage count) */ 630cea7daa3SToshiyuki Okajima if (!atomic_inc_not_zero(&keyring->usage)) 631cea7daa3SToshiyuki Okajima continue; 63231d5a79dSDavid Howells keyring->last_used_at = current_kernel_time().tv_sec; 633cea7daa3SToshiyuki Okajima goto out; 6341da177e4SLinus Torvalds } 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds keyring = ERR_PTR(-ENOKEY); 638cea7daa3SToshiyuki Okajima out: 639cea7daa3SToshiyuki Okajima read_unlock(&keyring_name_lock); 6401da177e4SLinus Torvalds return keyring; 641a8b17ed0SDavid Howells } 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds /* 644973c9f4fSDavid Howells * See if a cycle will will be created by inserting acyclic tree B in acyclic 645973c9f4fSDavid Howells * tree A at the topmost level (ie: as a direct child of A). 646973c9f4fSDavid Howells * 647973c9f4fSDavid Howells * Since we are adding B to A at the top level, checking for cycles should just 648973c9f4fSDavid Howells * be a matter of seeing if node A is somewhere in tree B. 6491da177e4SLinus Torvalds */ 6501da177e4SLinus Torvalds static int keyring_detect_cycle(struct key *A, struct key *B) 6511da177e4SLinus Torvalds { 6521da177e4SLinus Torvalds struct { 65376d8aeabSDavid Howells struct keyring_list *keylist; 6541da177e4SLinus Torvalds int kix; 6551da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds struct keyring_list *keylist; 6581da177e4SLinus Torvalds struct key *subtree, *key; 659efde8b6eSDavid Howells int sp, nkeys, kix, ret; 6601da177e4SLinus Torvalds 66176d8aeabSDavid Howells rcu_read_lock(); 66276d8aeabSDavid Howells 6631da177e4SLinus Torvalds ret = -EDEADLK; 6641da177e4SLinus Torvalds if (A == B) 66576d8aeabSDavid Howells goto cycle_detected; 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds subtree = B; 6681da177e4SLinus Torvalds sp = 0; 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds /* start processing a new keyring */ 6711da177e4SLinus Torvalds descend: 67276d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) 6731da177e4SLinus Torvalds goto not_this_keyring; 6741da177e4SLinus Torvalds 67576d8aeabSDavid Howells keylist = rcu_dereference(subtree->payload.subscriptions); 6761da177e4SLinus Torvalds if (!keylist) 6771da177e4SLinus Torvalds goto not_this_keyring; 6781da177e4SLinus Torvalds kix = 0; 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds ascend: 6811da177e4SLinus Torvalds /* iterate through the remaining keys in this keyring */ 682efde8b6eSDavid Howells nkeys = keylist->nkeys; 683efde8b6eSDavid Howells smp_rmb(); 684efde8b6eSDavid Howells for (; kix < nkeys; kix++) { 685233e4735SDavid Howells key = rcu_dereference(keylist->keys[kix]); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds if (key == A) 6881da177e4SLinus Torvalds goto cycle_detected; 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* recursively check nested keyrings */ 6911da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 6921da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 6931da177e4SLinus Torvalds goto too_deep; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds /* stack the current position */ 69676d8aeabSDavid Howells stack[sp].keylist = keylist; 6971da177e4SLinus Torvalds stack[sp].kix = kix; 6981da177e4SLinus Torvalds sp++; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds /* begin again with the new keyring */ 7011da177e4SLinus Torvalds subtree = key; 7021da177e4SLinus Torvalds goto descend; 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 7071da177e4SLinus Torvalds * matching key */ 7081da177e4SLinus Torvalds not_this_keyring: 7091da177e4SLinus Torvalds if (sp > 0) { 7101da177e4SLinus Torvalds /* resume the checking of a keyring higher up in the tree */ 7111da177e4SLinus Torvalds sp--; 71276d8aeabSDavid Howells keylist = stack[sp].keylist; 7131da177e4SLinus Torvalds kix = stack[sp].kix + 1; 7141da177e4SLinus Torvalds goto ascend; 7151da177e4SLinus Torvalds } 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds ret = 0; /* no cycles detected */ 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds error: 72076d8aeabSDavid Howells rcu_read_unlock(); 7211da177e4SLinus Torvalds return ret; 7221da177e4SLinus Torvalds 7231da177e4SLinus Torvalds too_deep: 7241da177e4SLinus Torvalds ret = -ELOOP; 72576d8aeabSDavid Howells goto error; 72676d8aeabSDavid Howells 7271da177e4SLinus Torvalds cycle_detected: 7281da177e4SLinus Torvalds ret = -EDEADLK; 7291da177e4SLinus Torvalds goto error; 730a8b17ed0SDavid Howells } 7311da177e4SLinus Torvalds 73276d8aeabSDavid Howells /* 733973c9f4fSDavid Howells * Dispose of a keyring list after the RCU grace period, freeing the unlinked 734cab8eb59SDavid Howells * key 735cab8eb59SDavid Howells */ 736cab8eb59SDavid Howells static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) 737cab8eb59SDavid Howells { 738cab8eb59SDavid Howells struct keyring_list *klist = 739cab8eb59SDavid Howells container_of(rcu, struct keyring_list, rcu); 740cab8eb59SDavid Howells 7414be929beSAlexey Dobriyan if (klist->delkey != USHRT_MAX) 742233e4735SDavid Howells key_put(rcu_access_pointer(klist->keys[klist->delkey])); 743cab8eb59SDavid Howells kfree(klist); 744f70e2e06SDavid Howells } 745cab8eb59SDavid Howells 746cab8eb59SDavid Howells /* 747973c9f4fSDavid Howells * Preallocate memory so that a key can be linked into to a keyring. 7481da177e4SLinus Torvalds */ 749*16feef43SDavid Howells int __key_link_begin(struct key *keyring, const struct keyring_index_key *index_key, 750*16feef43SDavid Howells unsigned long *_prealloc) 751f70e2e06SDavid Howells __acquires(&keyring->sem) 752423b9788SDavid Howells __acquires(&keyring_serialise_link_sem) 7531da177e4SLinus Torvalds { 7541da177e4SLinus Torvalds struct keyring_list *klist, *nklist; 755ceb73c12SDavid Howells unsigned long prealloc; 7561da177e4SLinus Torvalds unsigned max; 75731d5a79dSDavid Howells time_t lowest_lru; 7581da177e4SLinus Torvalds size_t size; 75931d5a79dSDavid Howells int loop, lru, ret; 7601da177e4SLinus Torvalds 761*16feef43SDavid Howells kenter("%d,%s,%s,", 762*16feef43SDavid Howells key_serial(keyring), index_key->type->name, index_key->description); 763f70e2e06SDavid Howells 764f70e2e06SDavid Howells if (keyring->type != &key_type_keyring) 765f70e2e06SDavid Howells return -ENOTDIR; 766f70e2e06SDavid Howells 767f70e2e06SDavid Howells down_write(&keyring->sem); 768f70e2e06SDavid Howells 7691da177e4SLinus Torvalds ret = -EKEYREVOKED; 77076d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 771f70e2e06SDavid Howells goto error_krsem; 7721da177e4SLinus Torvalds 773f70e2e06SDavid Howells /* serialise link/link calls to prevent parallel calls causing a cycle 774f70e2e06SDavid Howells * when linking two keyring in opposite orders */ 775*16feef43SDavid Howells if (index_key->type == &key_type_keyring) 7761da177e4SLinus Torvalds down_write(&keyring_serialise_link_sem); 7771da177e4SLinus Torvalds 778f70e2e06SDavid Howells klist = rcu_dereference_locked_keyring(keyring); 7791da177e4SLinus Torvalds 780cab8eb59SDavid Howells /* see if there's a matching key we can displace */ 78131d5a79dSDavid Howells lru = -1; 782cab8eb59SDavid Howells if (klist && klist->nkeys > 0) { 78331d5a79dSDavid Howells lowest_lru = TIME_T_MAX; 784cab8eb59SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 785233e4735SDavid Howells struct key *key = rcu_deref_link_locked(klist, loop, 786233e4735SDavid Howells keyring); 787*16feef43SDavid Howells if (key->type == index_key->type && 788*16feef43SDavid Howells strcmp(key->description, index_key->description) == 0) { 789233e4735SDavid Howells /* Found a match - we'll replace the link with 790233e4735SDavid Howells * one to the new key. We record the slot 791233e4735SDavid Howells * position. 792233e4735SDavid Howells */ 793233e4735SDavid Howells klist->delkey = loop; 794233e4735SDavid Howells prealloc = 0; 795cab8eb59SDavid Howells goto done; 796cab8eb59SDavid Howells } 79731d5a79dSDavid Howells if (key->last_used_at < lowest_lru) { 79831d5a79dSDavid Howells lowest_lru = key->last_used_at; 79931d5a79dSDavid Howells lru = loop; 800cab8eb59SDavid Howells } 801cab8eb59SDavid Howells } 80231d5a79dSDavid Howells } 80331d5a79dSDavid Howells 80431d5a79dSDavid Howells /* If the keyring is full then do an LRU discard */ 80531d5a79dSDavid Howells if (klist && 80631d5a79dSDavid Howells klist->nkeys == klist->maxkeys && 80731d5a79dSDavid Howells klist->maxkeys >= MAX_KEYRING_LINKS) { 80831d5a79dSDavid Howells kdebug("LRU discard %d\n", lru); 80931d5a79dSDavid Howells klist->delkey = lru; 81031d5a79dSDavid Howells prealloc = 0; 81131d5a79dSDavid Howells goto done; 81231d5a79dSDavid Howells } 813cab8eb59SDavid Howells 8141da177e4SLinus Torvalds /* check that we aren't going to overrun the user's quota */ 8151da177e4SLinus Torvalds ret = key_payload_reserve(keyring, 8161da177e4SLinus Torvalds keyring->datalen + KEYQUOTA_LINK_BYTES); 8171da177e4SLinus Torvalds if (ret < 0) 818f70e2e06SDavid Howells goto error_sem; 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds if (klist && klist->nkeys < klist->maxkeys) { 821f70e2e06SDavid Howells /* there's sufficient slack space to append directly */ 822233e4735SDavid Howells klist->delkey = klist->nkeys; 823ceb73c12SDavid Howells prealloc = KEY_LINK_FIXQUOTA; 824512ea3bcSChihau Chau } else { 8251da177e4SLinus Torvalds /* grow the key list */ 8261da177e4SLinus Torvalds max = 4; 82731d5a79dSDavid Howells if (klist) { 8281da177e4SLinus Torvalds max += klist->maxkeys; 82931d5a79dSDavid Howells if (max > MAX_KEYRING_LINKS) 83031d5a79dSDavid Howells max = MAX_KEYRING_LINKS; 83131d5a79dSDavid Howells BUG_ON(max <= klist->maxkeys); 83231d5a79dSDavid Howells } 8331da177e4SLinus Torvalds 834a4014d8fSDavid Howells size = sizeof(*klist) + sizeof(struct key *) * max; 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds ret = -ENOMEM; 8371da177e4SLinus Torvalds nklist = kmalloc(size, GFP_KERNEL); 8381da177e4SLinus Torvalds if (!nklist) 839f70e2e06SDavid Howells goto error_quota; 8401da177e4SLinus Torvalds 841f70e2e06SDavid Howells nklist->maxkeys = max; 8421da177e4SLinus Torvalds if (klist) { 843f70e2e06SDavid Howells memcpy(nklist->keys, klist->keys, 8441da177e4SLinus Torvalds sizeof(struct key *) * klist->nkeys); 845f70e2e06SDavid Howells nklist->delkey = klist->nkeys; 846f70e2e06SDavid Howells nklist->nkeys = klist->nkeys + 1; 8474be929beSAlexey Dobriyan klist->delkey = USHRT_MAX; 848f70e2e06SDavid Howells } else { 849f70e2e06SDavid Howells nklist->nkeys = 1; 850f70e2e06SDavid Howells nklist->delkey = 0; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds /* add the key into the new space */ 854233e4735SDavid Howells RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); 855233e4735SDavid Howells prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; 8561da177e4SLinus Torvalds } 8571da177e4SLinus Torvalds 858cab8eb59SDavid Howells done: 859ceb73c12SDavid Howells *_prealloc = prealloc; 860f70e2e06SDavid Howells kleave(" = 0"); 861f70e2e06SDavid Howells return 0; 8621da177e4SLinus Torvalds 863f70e2e06SDavid Howells error_quota: 8641da177e4SLinus Torvalds /* undo the quota changes */ 8651da177e4SLinus Torvalds key_payload_reserve(keyring, 8661da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 867f70e2e06SDavid Howells error_sem: 868*16feef43SDavid Howells if (index_key->type == &key_type_keyring) 869f70e2e06SDavid Howells up_write(&keyring_serialise_link_sem); 870f70e2e06SDavid Howells error_krsem: 871f70e2e06SDavid Howells up_write(&keyring->sem); 872f70e2e06SDavid Howells kleave(" = %d", ret); 873f70e2e06SDavid Howells return ret; 874f70e2e06SDavid Howells } 8751da177e4SLinus Torvalds 876f70e2e06SDavid Howells /* 877973c9f4fSDavid Howells * Check already instantiated keys aren't going to be a problem. 878973c9f4fSDavid Howells * 879973c9f4fSDavid Howells * The caller must have called __key_link_begin(). Don't need to call this for 880973c9f4fSDavid Howells * keys that were created since __key_link_begin() was called. 881f70e2e06SDavid Howells */ 882f70e2e06SDavid Howells int __key_link_check_live_key(struct key *keyring, struct key *key) 883f70e2e06SDavid Howells { 884f70e2e06SDavid Howells if (key->type == &key_type_keyring) 885f70e2e06SDavid Howells /* check that we aren't going to create a cycle by linking one 886f70e2e06SDavid Howells * keyring to another */ 887f70e2e06SDavid Howells return keyring_detect_cycle(keyring, key); 888f70e2e06SDavid Howells return 0; 889f70e2e06SDavid Howells } 8901da177e4SLinus Torvalds 891f70e2e06SDavid Howells /* 892973c9f4fSDavid Howells * Link a key into to a keyring. 893973c9f4fSDavid Howells * 894973c9f4fSDavid Howells * Must be called with __key_link_begin() having being called. Discards any 895973c9f4fSDavid Howells * already extant link to matching key if there is one, so that each keyring 896973c9f4fSDavid Howells * holds at most one link to any given key of a particular type+description 897973c9f4fSDavid Howells * combination. 898f70e2e06SDavid Howells */ 899f70e2e06SDavid Howells void __key_link(struct key *keyring, struct key *key, 900ceb73c12SDavid Howells unsigned long *_prealloc) 901f70e2e06SDavid Howells { 902f70e2e06SDavid Howells struct keyring_list *klist, *nklist; 903233e4735SDavid Howells struct key *discard; 904f70e2e06SDavid Howells 905ceb73c12SDavid Howells nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); 906ceb73c12SDavid Howells *_prealloc = 0; 907f70e2e06SDavid Howells 908f70e2e06SDavid Howells kenter("%d,%d,%p", keyring->serial, key->serial, nklist); 909f70e2e06SDavid Howells 9106d528b08SDavid Howells klist = rcu_dereference_locked_keyring(keyring); 911f70e2e06SDavid Howells 912f70e2e06SDavid Howells atomic_inc(&key->usage); 91331d5a79dSDavid Howells keyring->last_used_at = key->last_used_at = 91431d5a79dSDavid Howells current_kernel_time().tv_sec; 915f70e2e06SDavid Howells 916f70e2e06SDavid Howells /* there's a matching key we can displace or an empty slot in a newly 917f70e2e06SDavid Howells * allocated list we can fill */ 918f70e2e06SDavid Howells if (nklist) { 919233e4735SDavid Howells kdebug("reissue %hu/%hu/%hu", 920f70e2e06SDavid Howells nklist->delkey, nklist->nkeys, nklist->maxkeys); 921f70e2e06SDavid Howells 922233e4735SDavid Howells RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); 923f70e2e06SDavid Howells 924f70e2e06SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 925f70e2e06SDavid Howells 926f70e2e06SDavid Howells /* dispose of the old keyring list and, if there was one, the 927f70e2e06SDavid Howells * displaced key */ 928f70e2e06SDavid Howells if (klist) { 929f70e2e06SDavid Howells kdebug("dispose %hu/%hu/%hu", 930f70e2e06SDavid Howells klist->delkey, klist->nkeys, klist->maxkeys); 931f70e2e06SDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 932f70e2e06SDavid Howells } 933233e4735SDavid Howells } else if (klist->delkey < klist->nkeys) { 934233e4735SDavid Howells kdebug("replace %hu/%hu/%hu", 935233e4735SDavid Howells klist->delkey, klist->nkeys, klist->maxkeys); 936233e4735SDavid Howells 937233e4735SDavid Howells discard = rcu_dereference_protected( 938233e4735SDavid Howells klist->keys[klist->delkey], 939233e4735SDavid Howells rwsem_is_locked(&keyring->sem)); 940233e4735SDavid Howells rcu_assign_pointer(klist->keys[klist->delkey], key); 941233e4735SDavid Howells /* The garbage collector will take care of RCU 942233e4735SDavid Howells * synchronisation */ 943233e4735SDavid Howells key_put(discard); 944f70e2e06SDavid Howells } else { 945f70e2e06SDavid Howells /* there's sufficient slack space to append directly */ 946233e4735SDavid Howells kdebug("append %hu/%hu/%hu", 947233e4735SDavid Howells klist->delkey, klist->nkeys, klist->maxkeys); 948233e4735SDavid Howells 949233e4735SDavid Howells RCU_INIT_POINTER(klist->keys[klist->delkey], key); 950f70e2e06SDavid Howells smp_wmb(); 951f70e2e06SDavid Howells klist->nkeys++; 952f70e2e06SDavid Howells } 953f70e2e06SDavid Howells } 954f70e2e06SDavid Howells 955f70e2e06SDavid Howells /* 956973c9f4fSDavid Howells * Finish linking a key into to a keyring. 957973c9f4fSDavid Howells * 958973c9f4fSDavid Howells * Must be called with __key_link_begin() having being called. 959f70e2e06SDavid Howells */ 960*16feef43SDavid Howells void __key_link_end(struct key *keyring, 961*16feef43SDavid Howells const struct keyring_index_key *index_key, 962ceb73c12SDavid Howells unsigned long prealloc) 963f70e2e06SDavid Howells __releases(&keyring->sem) 964423b9788SDavid Howells __releases(&keyring_serialise_link_sem) 965f70e2e06SDavid Howells { 966*16feef43SDavid Howells BUG_ON(index_key->type == NULL); 967*16feef43SDavid Howells BUG_ON(index_key->type->name == NULL); 968*16feef43SDavid Howells kenter("%d,%s,%lx", keyring->serial, index_key->type->name, prealloc); 969f70e2e06SDavid Howells 970*16feef43SDavid Howells if (index_key->type == &key_type_keyring) 971f70e2e06SDavid Howells up_write(&keyring_serialise_link_sem); 972f70e2e06SDavid Howells 973f70e2e06SDavid Howells if (prealloc) { 974ceb73c12SDavid Howells if (prealloc & KEY_LINK_FIXQUOTA) 975f70e2e06SDavid Howells key_payload_reserve(keyring, 976ceb73c12SDavid Howells keyring->datalen - 977ceb73c12SDavid Howells KEYQUOTA_LINK_BYTES); 978ceb73c12SDavid Howells kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA)); 979f70e2e06SDavid Howells } 980f70e2e06SDavid Howells up_write(&keyring->sem); 981f70e2e06SDavid Howells } 982f70e2e06SDavid Howells 983973c9f4fSDavid Howells /** 984973c9f4fSDavid Howells * key_link - Link a key to a keyring 985973c9f4fSDavid Howells * @keyring: The keyring to make the link in. 986973c9f4fSDavid Howells * @key: The key to link to. 987973c9f4fSDavid Howells * 988973c9f4fSDavid Howells * Make a link in a keyring to a key, such that the keyring holds a reference 989973c9f4fSDavid Howells * on that key and the key can potentially be found by searching that keyring. 990973c9f4fSDavid Howells * 991973c9f4fSDavid Howells * This function will write-lock the keyring's semaphore and will consume some 992973c9f4fSDavid Howells * of the user's key data quota to hold the link. 993973c9f4fSDavid Howells * 994973c9f4fSDavid Howells * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, 995973c9f4fSDavid Howells * -EKEYREVOKED if the keyring has been revoked, -ENFILE if the keyring is 996973c9f4fSDavid Howells * full, -EDQUOT if there is insufficient key data quota remaining to add 997973c9f4fSDavid Howells * another link or -ENOMEM if there's insufficient memory. 998973c9f4fSDavid Howells * 999973c9f4fSDavid Howells * It is assumed that the caller has checked that it is permitted for a link to 1000973c9f4fSDavid Howells * be made (the keyring should have Write permission and the key Link 1001973c9f4fSDavid Howells * permission). 10021da177e4SLinus Torvalds */ 10031da177e4SLinus Torvalds int key_link(struct key *keyring, struct key *key) 10041da177e4SLinus Torvalds { 1005ceb73c12SDavid Howells unsigned long prealloc; 10061da177e4SLinus Torvalds int ret; 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds key_check(keyring); 10091da177e4SLinus Torvalds key_check(key); 10101da177e4SLinus Torvalds 1011*16feef43SDavid Howells ret = __key_link_begin(keyring, &key->index_key, &prealloc); 1012f70e2e06SDavid Howells if (ret == 0) { 1013f70e2e06SDavid Howells ret = __key_link_check_live_key(keyring, key); 1014f70e2e06SDavid Howells if (ret == 0) 1015f70e2e06SDavid Howells __key_link(keyring, key, &prealloc); 1016*16feef43SDavid Howells __key_link_end(keyring, &key->index_key, prealloc); 1017f70e2e06SDavid Howells } 10181da177e4SLinus Torvalds 10191da177e4SLinus Torvalds return ret; 1020f70e2e06SDavid Howells } 10211da177e4SLinus Torvalds EXPORT_SYMBOL(key_link); 10221da177e4SLinus Torvalds 1023973c9f4fSDavid Howells /** 1024973c9f4fSDavid Howells * key_unlink - Unlink the first link to a key from a keyring. 1025973c9f4fSDavid Howells * @keyring: The keyring to remove the link from. 1026973c9f4fSDavid Howells * @key: The key the link is to. 1027973c9f4fSDavid Howells * 1028973c9f4fSDavid Howells * Remove a link from a keyring to a key. 1029973c9f4fSDavid Howells * 1030973c9f4fSDavid Howells * This function will write-lock the keyring's semaphore. 1031973c9f4fSDavid Howells * 1032973c9f4fSDavid Howells * Returns 0 if successful, -ENOTDIR if the keyring isn't a keyring, -ENOENT if 1033973c9f4fSDavid Howells * the key isn't linked to by the keyring or -ENOMEM if there's insufficient 1034973c9f4fSDavid Howells * memory. 1035973c9f4fSDavid Howells * 1036973c9f4fSDavid Howells * It is assumed that the caller has checked that it is permitted for a link to 1037973c9f4fSDavid Howells * be removed (the keyring should have Write permission; no permissions are 1038973c9f4fSDavid Howells * required on the key). 10391da177e4SLinus Torvalds */ 10401da177e4SLinus Torvalds int key_unlink(struct key *keyring, struct key *key) 10411da177e4SLinus Torvalds { 104276d8aeabSDavid Howells struct keyring_list *klist, *nklist; 10431da177e4SLinus Torvalds int loop, ret; 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds key_check(keyring); 10461da177e4SLinus Torvalds key_check(key); 10471da177e4SLinus Torvalds 10481da177e4SLinus Torvalds ret = -ENOTDIR; 10491da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 10501da177e4SLinus Torvalds goto error; 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds down_write(&keyring->sem); 10531da177e4SLinus Torvalds 1054f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 10551da177e4SLinus Torvalds if (klist) { 10561da177e4SLinus Torvalds /* search the keyring for the key */ 10571da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) 1058233e4735SDavid Howells if (rcu_access_pointer(klist->keys[loop]) == key) 10591da177e4SLinus Torvalds goto key_is_present; 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds up_write(&keyring->sem); 10631da177e4SLinus Torvalds ret = -ENOENT; 10641da177e4SLinus Torvalds goto error; 10651da177e4SLinus Torvalds 10661da177e4SLinus Torvalds key_is_present: 106776d8aeabSDavid Howells /* we need to copy the key list for RCU purposes */ 1068a4014d8fSDavid Howells nklist = kmalloc(sizeof(*klist) + 1069a4014d8fSDavid Howells sizeof(struct key *) * klist->maxkeys, 107076d8aeabSDavid Howells GFP_KERNEL); 107176d8aeabSDavid Howells if (!nklist) 107276d8aeabSDavid Howells goto nomem; 107376d8aeabSDavid Howells nklist->maxkeys = klist->maxkeys; 107476d8aeabSDavid Howells nklist->nkeys = klist->nkeys - 1; 107576d8aeabSDavid Howells 107676d8aeabSDavid Howells if (loop > 0) 107776d8aeabSDavid Howells memcpy(&nklist->keys[0], 107876d8aeabSDavid Howells &klist->keys[0], 1079a4014d8fSDavid Howells loop * sizeof(struct key *)); 108076d8aeabSDavid Howells 108176d8aeabSDavid Howells if (loop < nklist->nkeys) 108276d8aeabSDavid Howells memcpy(&nklist->keys[loop], 108376d8aeabSDavid Howells &klist->keys[loop + 1], 1084a4014d8fSDavid Howells (nklist->nkeys - loop) * sizeof(struct key *)); 108576d8aeabSDavid Howells 10861da177e4SLinus Torvalds /* adjust the user's quota */ 10871da177e4SLinus Torvalds key_payload_reserve(keyring, 10881da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 10891da177e4SLinus Torvalds 109076d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 10911da177e4SLinus Torvalds 10921da177e4SLinus Torvalds up_write(&keyring->sem); 109376d8aeabSDavid Howells 109476d8aeabSDavid Howells /* schedule for later cleanup */ 109576d8aeabSDavid Howells klist->delkey = loop; 109676d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 109776d8aeabSDavid Howells 10981da177e4SLinus Torvalds ret = 0; 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds error: 11011da177e4SLinus Torvalds return ret; 110276d8aeabSDavid Howells nomem: 110376d8aeabSDavid Howells ret = -ENOMEM; 110476d8aeabSDavid Howells up_write(&keyring->sem); 110576d8aeabSDavid Howells goto error; 1106a8b17ed0SDavid Howells } 11071da177e4SLinus Torvalds EXPORT_SYMBOL(key_unlink); 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds /* 1110973c9f4fSDavid Howells * Dispose of a keyring list after the RCU grace period, releasing the keys it 1111973c9f4fSDavid Howells * links to. 111276d8aeabSDavid Howells */ 111376d8aeabSDavid Howells static void keyring_clear_rcu_disposal(struct rcu_head *rcu) 111476d8aeabSDavid Howells { 111576d8aeabSDavid Howells struct keyring_list *klist; 111676d8aeabSDavid Howells int loop; 111776d8aeabSDavid Howells 111876d8aeabSDavid Howells klist = container_of(rcu, struct keyring_list, rcu); 111976d8aeabSDavid Howells 112076d8aeabSDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 1121233e4735SDavid Howells key_put(rcu_access_pointer(klist->keys[loop])); 112276d8aeabSDavid Howells 112376d8aeabSDavid Howells kfree(klist); 1124a8b17ed0SDavid Howells } 112576d8aeabSDavid Howells 1126973c9f4fSDavid Howells /** 1127973c9f4fSDavid Howells * keyring_clear - Clear a keyring 1128973c9f4fSDavid Howells * @keyring: The keyring to clear. 1129973c9f4fSDavid Howells * 1130973c9f4fSDavid Howells * Clear the contents of the specified keyring. 1131973c9f4fSDavid Howells * 1132973c9f4fSDavid Howells * Returns 0 if successful or -ENOTDIR if the keyring isn't a keyring. 11331da177e4SLinus Torvalds */ 11341da177e4SLinus Torvalds int keyring_clear(struct key *keyring) 11351da177e4SLinus Torvalds { 11361da177e4SLinus Torvalds struct keyring_list *klist; 113776d8aeabSDavid Howells int ret; 11381da177e4SLinus Torvalds 11391da177e4SLinus Torvalds ret = -ENOTDIR; 11401da177e4SLinus Torvalds if (keyring->type == &key_type_keyring) { 11411da177e4SLinus Torvalds /* detach the pointer block with the locks held */ 11421da177e4SLinus Torvalds down_write(&keyring->sem); 11431da177e4SLinus Torvalds 1144f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 11451da177e4SLinus Torvalds if (klist) { 11461da177e4SLinus Torvalds /* adjust the quota */ 11471da177e4SLinus Torvalds key_payload_reserve(keyring, 11481da177e4SLinus Torvalds sizeof(struct keyring_list)); 11491da177e4SLinus Torvalds 115076d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, 115176d8aeabSDavid Howells NULL); 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds up_write(&keyring->sem); 11551da177e4SLinus Torvalds 11561da177e4SLinus Torvalds /* free the keys after the locks have been dropped */ 115776d8aeabSDavid Howells if (klist) 115876d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 11591da177e4SLinus Torvalds 11601da177e4SLinus Torvalds ret = 0; 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds return ret; 1164a8b17ed0SDavid Howells } 11651da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_clear); 116631204ed9SDavid Howells 116731204ed9SDavid Howells /* 1168973c9f4fSDavid Howells * Dispose of the links from a revoked keyring. 1169973c9f4fSDavid Howells * 1170973c9f4fSDavid Howells * This is called with the key sem write-locked. 117131204ed9SDavid Howells */ 117231204ed9SDavid Howells static void keyring_revoke(struct key *keyring) 117331204ed9SDavid Howells { 1174f0641cbaSDavid Howells struct keyring_list *klist; 1175f0641cbaSDavid Howells 1176f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 117731204ed9SDavid Howells 117831204ed9SDavid Howells /* adjust the quota */ 117931204ed9SDavid Howells key_payload_reserve(keyring, 0); 118031204ed9SDavid Howells 118131204ed9SDavid Howells if (klist) { 118231204ed9SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, NULL); 118331204ed9SDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 118431204ed9SDavid Howells } 1185a8b17ed0SDavid Howells } 11865d135440SDavid Howells 11875d135440SDavid Howells /* 1188973c9f4fSDavid Howells * Collect garbage from the contents of a keyring, replacing the old list with 1189973c9f4fSDavid Howells * a new one with the pointers all shuffled down. 1190973c9f4fSDavid Howells * 1191973c9f4fSDavid Howells * Dead keys are classed as oned that are flagged as being dead or are revoked, 1192973c9f4fSDavid Howells * expired or negative keys that were revoked or expired before the specified 1193973c9f4fSDavid Howells * limit. 11945d135440SDavid Howells */ 11955d135440SDavid Howells void keyring_gc(struct key *keyring, time_t limit) 11965d135440SDavid Howells { 11975d135440SDavid Howells struct keyring_list *klist, *new; 11985d135440SDavid Howells struct key *key; 11995d135440SDavid Howells int loop, keep, max; 12005d135440SDavid Howells 1201c08ef808SDavid Howells kenter("{%x,%s}", key_serial(keyring), keyring->description); 12025d135440SDavid Howells 12035d135440SDavid Howells down_write(&keyring->sem); 12045d135440SDavid Howells 1205f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 12065d135440SDavid Howells if (!klist) 1207c08ef808SDavid Howells goto no_klist; 12085d135440SDavid Howells 12095d135440SDavid Howells /* work out how many subscriptions we're keeping */ 12105d135440SDavid Howells keep = 0; 12115d135440SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 1212233e4735SDavid Howells if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), 1213233e4735SDavid Howells limit)) 12145d135440SDavid Howells keep++; 12155d135440SDavid Howells 12165d135440SDavid Howells if (keep == klist->nkeys) 12175d135440SDavid Howells goto just_return; 12185d135440SDavid Howells 12195d135440SDavid Howells /* allocate a new keyring payload */ 12205d135440SDavid Howells max = roundup(keep, 4); 12215d135440SDavid Howells new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), 12225d135440SDavid Howells GFP_KERNEL); 12235d135440SDavid Howells if (!new) 1224c08ef808SDavid Howells goto nomem; 12255d135440SDavid Howells new->maxkeys = max; 12265d135440SDavid Howells new->nkeys = 0; 12275d135440SDavid Howells new->delkey = 0; 12285d135440SDavid Howells 12295d135440SDavid Howells /* install the live keys 12305d135440SDavid Howells * - must take care as expired keys may be updated back to life 12315d135440SDavid Howells */ 12325d135440SDavid Howells keep = 0; 12335d135440SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 1234233e4735SDavid Howells key = rcu_deref_link_locked(klist, loop, keyring); 12355d135440SDavid Howells if (!key_is_dead(key, limit)) { 12365d135440SDavid Howells if (keep >= max) 12375d135440SDavid Howells goto discard_new; 1238233e4735SDavid Howells RCU_INIT_POINTER(new->keys[keep++], key_get(key)); 12395d135440SDavid Howells } 12405d135440SDavid Howells } 12415d135440SDavid Howells new->nkeys = keep; 12425d135440SDavid Howells 12435d135440SDavid Howells /* adjust the quota */ 12445d135440SDavid Howells key_payload_reserve(keyring, 12455d135440SDavid Howells sizeof(struct keyring_list) + 12465d135440SDavid Howells KEYQUOTA_LINK_BYTES * keep); 12475d135440SDavid Howells 12485d135440SDavid Howells if (keep == 0) { 12495d135440SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, NULL); 12505d135440SDavid Howells kfree(new); 12515d135440SDavid Howells } else { 12525d135440SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, new); 12535d135440SDavid Howells } 12545d135440SDavid Howells 12555d135440SDavid Howells up_write(&keyring->sem); 12565d135440SDavid Howells 12575d135440SDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 12585d135440SDavid Howells kleave(" [yes]"); 12595d135440SDavid Howells return; 12605d135440SDavid Howells 12615d135440SDavid Howells discard_new: 12625d135440SDavid Howells new->nkeys = keep; 12635d135440SDavid Howells keyring_clear_rcu_disposal(&new->rcu); 1264c08ef808SDavid Howells up_write(&keyring->sem); 1265c08ef808SDavid Howells kleave(" [discard]"); 1266c08ef808SDavid Howells return; 1267c08ef808SDavid Howells 12685d135440SDavid Howells just_return: 12695d135440SDavid Howells up_write(&keyring->sem); 1270c08ef808SDavid Howells kleave(" [no dead]"); 1271c08ef808SDavid Howells return; 1272c08ef808SDavid Howells 1273c08ef808SDavid Howells no_klist: 1274c08ef808SDavid Howells up_write(&keyring->sem); 1275c08ef808SDavid Howells kleave(" [no_klist]"); 1276c08ef808SDavid Howells return; 1277c08ef808SDavid Howells 1278c08ef808SDavid Howells nomem: 1279c08ef808SDavid Howells up_write(&keyring->sem); 1280c08ef808SDavid Howells kleave(" [oom]"); 12815d135440SDavid Howells } 1282