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> 201da177e4SLinus Torvalds #include <asm/uaccess.h> 211da177e4SLinus Torvalds #include "internal.h" 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds /* 241da177e4SLinus Torvalds * when plumbing the depths of the key tree, this sets a hard limit set on how 251da177e4SLinus Torvalds * deep we're willing to go 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds #define KEYRING_SEARCH_MAX_DEPTH 6 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* 301da177e4SLinus Torvalds * we keep all named keyrings in a hash to speed looking them up 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds #define KEYRING_NAME_HASH_SIZE (1 << 5) 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; 351da177e4SLinus Torvalds static DEFINE_RWLOCK(keyring_name_lock); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static inline unsigned keyring_hash(const char *desc) 381da177e4SLinus Torvalds { 391da177e4SLinus Torvalds unsigned bucket = 0; 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds for (; *desc; desc++) 421da177e4SLinus Torvalds bucket += (unsigned char) *desc; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds return bucket & (KEYRING_NAME_HASH_SIZE - 1); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* 481da177e4SLinus Torvalds * the keyring type definition 491da177e4SLinus Torvalds */ 501da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 511da177e4SLinus Torvalds const void *data, size_t datalen); 521da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *criterion); 5331204ed9SDavid Howells static void keyring_revoke(struct key *keyring); 541da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring); 551da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m); 561da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 571da177e4SLinus Torvalds char __user *buffer, size_t buflen); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds struct key_type key_type_keyring = { 601da177e4SLinus Torvalds .name = "keyring", 611da177e4SLinus Torvalds .def_datalen = sizeof(struct keyring_list), 621da177e4SLinus Torvalds .instantiate = keyring_instantiate, 631da177e4SLinus Torvalds .match = keyring_match, 6431204ed9SDavid Howells .revoke = keyring_revoke, 651da177e4SLinus Torvalds .destroy = keyring_destroy, 661da177e4SLinus Torvalds .describe = keyring_describe, 671da177e4SLinus Torvalds .read = keyring_read, 681da177e4SLinus Torvalds }; 691da177e4SLinus Torvalds 707318226eSDavid Howells EXPORT_SYMBOL(key_type_keyring); 717318226eSDavid Howells 721da177e4SLinus Torvalds /* 731da177e4SLinus Torvalds * semaphore to serialise link/link calls to prevent two link calls in parallel 741da177e4SLinus Torvalds * introducing a cycle 751da177e4SLinus Torvalds */ 761ae8f407SAdrian Bunk static DECLARE_RWSEM(keyring_serialise_link_sem); 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /*****************************************************************************/ 791da177e4SLinus Torvalds /* 801da177e4SLinus Torvalds * publish the name of a keyring so that it can be found by name (if it has 811da177e4SLinus Torvalds * one) 821da177e4SLinus Torvalds */ 8369664cf1SDavid Howells static void keyring_publish_name(struct key *keyring) 841da177e4SLinus Torvalds { 851da177e4SLinus Torvalds int bucket; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds if (keyring->description) { 881da177e4SLinus Torvalds bucket = keyring_hash(keyring->description); 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds write_lock(&keyring_name_lock); 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds if (!keyring_name_hash[bucket].next) 931da177e4SLinus Torvalds INIT_LIST_HEAD(&keyring_name_hash[bucket]); 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds list_add_tail(&keyring->type_data.link, 961da177e4SLinus Torvalds &keyring_name_hash[bucket]); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds } /* end keyring_publish_name() */ 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /*****************************************************************************/ 1041da177e4SLinus Torvalds /* 1051da177e4SLinus Torvalds * initialise a keyring 1061da177e4SLinus Torvalds * - we object if we were given any data 1071da177e4SLinus Torvalds */ 1081da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 1091da177e4SLinus Torvalds const void *data, size_t datalen) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds int ret; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds ret = -EINVAL; 1141da177e4SLinus Torvalds if (datalen == 0) { 1151da177e4SLinus Torvalds /* make the keyring available by name if it has one */ 1161da177e4SLinus Torvalds keyring_publish_name(keyring); 1171da177e4SLinus Torvalds ret = 0; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds return ret; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds } /* end keyring_instantiate() */ 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /*****************************************************************************/ 1251da177e4SLinus Torvalds /* 1261da177e4SLinus Torvalds * match keyrings on their name 1271da177e4SLinus Torvalds */ 1281da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *description) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds return keyring->description && 1311da177e4SLinus Torvalds strcmp(keyring->description, description) == 0; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds } /* end keyring_match() */ 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /*****************************************************************************/ 1361da177e4SLinus Torvalds /* 1371da177e4SLinus Torvalds * dispose of the data dangling from the corpse of a keyring 1381da177e4SLinus Torvalds */ 1391da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds struct keyring_list *klist; 1421da177e4SLinus Torvalds int loop; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds if (keyring->description) { 1451da177e4SLinus Torvalds write_lock(&keyring_name_lock); 14694efe72fSDavid Howells 14794efe72fSDavid Howells if (keyring->type_data.link.next != NULL && 14894efe72fSDavid Howells !list_empty(&keyring->type_data.link)) 1491da177e4SLinus Torvalds list_del(&keyring->type_data.link); 15094efe72fSDavid Howells 1511da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 154e7b0a61bSPaul E. McKenney klist = rcu_dereference_check(keyring->payload.subscriptions, 155e7b0a61bSPaul E. McKenney rcu_read_lock_held() || 156e7b0a61bSPaul E. McKenney atomic_read(&keyring->usage) == 0); 1571da177e4SLinus Torvalds if (klist) { 1581da177e4SLinus Torvalds for (loop = klist->nkeys - 1; loop >= 0; loop--) 1591da177e4SLinus Torvalds key_put(klist->keys[loop]); 1601da177e4SLinus Torvalds kfree(klist); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds } /* end keyring_destroy() */ 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds /*****************************************************************************/ 1661da177e4SLinus Torvalds /* 1671da177e4SLinus Torvalds * describe the keyring 1681da177e4SLinus Torvalds */ 1691da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds struct keyring_list *klist; 1721da177e4SLinus Torvalds 173*c8563473Swzt.wzt@gmail.com if (keyring->description) 1741da177e4SLinus Torvalds seq_puts(m, keyring->description); 175*c8563473Swzt.wzt@gmail.com else 1761da177e4SLinus Torvalds seq_puts(m, "[anon]"); 1771da177e4SLinus Torvalds 17876d8aeabSDavid Howells rcu_read_lock(); 17976d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 1801da177e4SLinus Torvalds if (klist) 1811da177e4SLinus Torvalds seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); 1821da177e4SLinus Torvalds else 1831da177e4SLinus Torvalds seq_puts(m, ": empty"); 18476d8aeabSDavid Howells rcu_read_unlock(); 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds } /* end keyring_describe() */ 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds /*****************************************************************************/ 1891da177e4SLinus Torvalds /* 1901da177e4SLinus Torvalds * read a list of key IDs from the keyring's contents 19176d8aeabSDavid Howells * - the keyring's semaphore is read-locked 1921da177e4SLinus Torvalds */ 1931da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 1941da177e4SLinus Torvalds char __user *buffer, size_t buflen) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds struct keyring_list *klist; 1971da177e4SLinus Torvalds struct key *key; 1981da177e4SLinus Torvalds size_t qty, tmp; 1991da177e4SLinus Torvalds int loop, ret; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds ret = 0; 20276d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds if (klist) { 2051da177e4SLinus Torvalds /* calculate how much data we could return */ 2061da177e4SLinus Torvalds qty = klist->nkeys * sizeof(key_serial_t); 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds if (buffer && buflen > 0) { 2091da177e4SLinus Torvalds if (buflen > qty) 2101da177e4SLinus Torvalds buflen = qty; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* copy the IDs of the subscribed keys into the 2131da177e4SLinus Torvalds * buffer */ 2141da177e4SLinus Torvalds ret = -EFAULT; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 2171da177e4SLinus Torvalds key = klist->keys[loop]; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds tmp = sizeof(key_serial_t); 2201da177e4SLinus Torvalds if (tmp > buflen) 2211da177e4SLinus Torvalds tmp = buflen; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds if (copy_to_user(buffer, 2241da177e4SLinus Torvalds &key->serial, 2251da177e4SLinus Torvalds tmp) != 0) 2261da177e4SLinus Torvalds goto error; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds buflen -= tmp; 2291da177e4SLinus Torvalds if (buflen == 0) 2301da177e4SLinus Torvalds break; 2311da177e4SLinus Torvalds buffer += tmp; 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds ret = qty; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds error: 2391da177e4SLinus Torvalds return ret; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds } /* end keyring_read() */ 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /*****************************************************************************/ 2441da177e4SLinus Torvalds /* 2451da177e4SLinus Torvalds * allocate a keyring and link into the destination keyring 2461da177e4SLinus Torvalds */ 2471da177e4SLinus Torvalds struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, 248d84f4f99SDavid Howells const struct cred *cred, unsigned long flags, 249d720024eSMichael LeMay struct key *dest) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds struct key *keyring; 2521da177e4SLinus Torvalds int ret; 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds keyring = key_alloc(&key_type_keyring, description, 255d84f4f99SDavid Howells uid, gid, cred, 25629db9190SDavid Howells (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, 2577e047ef5SDavid Howells flags); 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds if (!IS_ERR(keyring)) { 2603e30148cSDavid Howells ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); 2611da177e4SLinus Torvalds if (ret < 0) { 2621da177e4SLinus Torvalds key_put(keyring); 2631da177e4SLinus Torvalds keyring = ERR_PTR(ret); 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds return keyring; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds } /* end keyring_alloc() */ 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds /*****************************************************************************/ 2721da177e4SLinus Torvalds /* 2731da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 2741da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 2751da177e4SLinus Torvalds * - we only find keys on which we have search permission 2761da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 2771da177e4SLinus Torvalds * feature of interest) matches 2783e30148cSDavid Howells * - we rely on RCU to prevent the keyring lists from disappearing on us 2791da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 2801da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 281664cceb0SDavid Howells * - we propagate the possession attribute from the keyring ref to the key ref 2821da177e4SLinus Torvalds */ 283664cceb0SDavid Howells key_ref_t keyring_search_aux(key_ref_t keyring_ref, 284d84f4f99SDavid Howells const struct cred *cred, 2851da177e4SLinus Torvalds struct key_type *type, 2861da177e4SLinus Torvalds const void *description, 2871da177e4SLinus Torvalds key_match_func_t match) 2881da177e4SLinus Torvalds { 2891da177e4SLinus Torvalds struct { 29076d8aeabSDavid Howells struct keyring_list *keylist; 2911da177e4SLinus Torvalds int kix; 2921da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds struct keyring_list *keylist; 2951da177e4SLinus Torvalds struct timespec now; 296dceba994SKevin Coffman unsigned long possessed, kflags; 297664cceb0SDavid Howells struct key *keyring, *key; 298664cceb0SDavid Howells key_ref_t key_ref; 2991da177e4SLinus Torvalds long err; 30076d8aeabSDavid Howells int sp, kix; 3011da177e4SLinus Torvalds 302664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 303664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 3041da177e4SLinus Torvalds key_check(keyring); 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds /* top keyring must have search permission to begin the search */ 307d84f4f99SDavid Howells err = key_task_permission(keyring_ref, cred, KEY_SEARCH); 30829db9190SDavid Howells if (err < 0) { 30929db9190SDavid Howells key_ref = ERR_PTR(err); 3101da177e4SLinus Torvalds goto error; 31129db9190SDavid Howells } 3121da177e4SLinus Torvalds 313664cceb0SDavid Howells key_ref = ERR_PTR(-ENOTDIR); 3141da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 3151da177e4SLinus Torvalds goto error; 3161da177e4SLinus Torvalds 317664cceb0SDavid Howells rcu_read_lock(); 318664cceb0SDavid Howells 3191da177e4SLinus Torvalds now = current_kernel_time(); 3201da177e4SLinus Torvalds err = -EAGAIN; 3211da177e4SLinus Torvalds sp = 0; 3221da177e4SLinus Torvalds 323dceba994SKevin Coffman /* firstly we should check to see if this top-level keyring is what we 324dceba994SKevin Coffman * are looking for */ 325dceba994SKevin Coffman key_ref = ERR_PTR(-EAGAIN); 326dceba994SKevin Coffman kflags = keyring->flags; 327dceba994SKevin Coffman if (keyring->type == type && match(keyring, description)) { 328dceba994SKevin Coffman key = keyring; 329dceba994SKevin Coffman 330dceba994SKevin Coffman /* check it isn't negative and hasn't expired or been 331dceba994SKevin Coffman * revoked */ 332dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_REVOKED)) 333dceba994SKevin Coffman goto error_2; 334dceba994SKevin Coffman if (key->expiry && now.tv_sec >= key->expiry) 335dceba994SKevin Coffman goto error_2; 336dceba994SKevin Coffman key_ref = ERR_PTR(-ENOKEY); 337dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_NEGATIVE)) 338dceba994SKevin Coffman goto error_2; 339dceba994SKevin Coffman goto found; 340dceba994SKevin Coffman } 341dceba994SKevin Coffman 342dceba994SKevin Coffman /* otherwise, the top keyring must not be revoked, expired, or 343dceba994SKevin Coffman * negatively instantiated if we are to search it */ 344dceba994SKevin Coffman key_ref = ERR_PTR(-EAGAIN); 345dceba994SKevin Coffman if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || 346dceba994SKevin Coffman (keyring->expiry && now.tv_sec >= keyring->expiry)) 347dceba994SKevin Coffman goto error_2; 348dceba994SKevin Coffman 3491da177e4SLinus Torvalds /* start processing a new keyring */ 3501da177e4SLinus Torvalds descend: 35176d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 3521da177e4SLinus Torvalds goto not_this_keyring; 3531da177e4SLinus Torvalds 35476d8aeabSDavid Howells keylist = rcu_dereference(keyring->payload.subscriptions); 3551da177e4SLinus Torvalds if (!keylist) 3561da177e4SLinus Torvalds goto not_this_keyring; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds /* iterate through the keys in this keyring first */ 3591da177e4SLinus Torvalds for (kix = 0; kix < keylist->nkeys; kix++) { 3601da177e4SLinus Torvalds key = keylist->keys[kix]; 361dceba994SKevin Coffman kflags = key->flags; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds /* ignore keys not of this type */ 3641da177e4SLinus Torvalds if (key->type != type) 3651da177e4SLinus Torvalds continue; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds /* skip revoked keys and expired keys */ 368dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_REVOKED)) 3691da177e4SLinus Torvalds continue; 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds if (key->expiry && now.tv_sec >= key->expiry) 3721da177e4SLinus Torvalds continue; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds /* keys that don't match */ 3751da177e4SLinus Torvalds if (!match(key, description)) 3761da177e4SLinus Torvalds continue; 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* key must have search permissions */ 37929db9190SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 380d84f4f99SDavid Howells cred, KEY_SEARCH) < 0) 3811da177e4SLinus Torvalds continue; 3821da177e4SLinus Torvalds 383dceba994SKevin Coffman /* we set a different error code if we pass a negative key */ 384dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_NEGATIVE)) { 3851da177e4SLinus Torvalds err = -ENOKEY; 3861da177e4SLinus Torvalds continue; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds goto found; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds /* search through the keyrings nested in this one */ 3931da177e4SLinus Torvalds kix = 0; 3941da177e4SLinus Torvalds ascend: 39576d8aeabSDavid Howells for (; kix < keylist->nkeys; kix++) { 3961da177e4SLinus Torvalds key = keylist->keys[kix]; 3971da177e4SLinus Torvalds if (key->type != &key_type_keyring) 39876d8aeabSDavid Howells continue; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* recursively search nested keyrings 4011da177e4SLinus Torvalds * - only search keyrings for which we have search permission 4021da177e4SLinus Torvalds */ 4031da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 40476d8aeabSDavid Howells continue; 4051da177e4SLinus Torvalds 4060f6ed7c2SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 407d84f4f99SDavid Howells cred, KEY_SEARCH) < 0) 40876d8aeabSDavid Howells continue; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds /* stack the current position */ 41176d8aeabSDavid Howells stack[sp].keylist = keylist; 4121da177e4SLinus Torvalds stack[sp].kix = kix; 4131da177e4SLinus Torvalds sp++; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* begin again with the new keyring */ 4161da177e4SLinus Torvalds keyring = key; 4171da177e4SLinus Torvalds goto descend; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 4211da177e4SLinus Torvalds * matching key */ 4221da177e4SLinus Torvalds not_this_keyring: 4231da177e4SLinus Torvalds if (sp > 0) { 4241da177e4SLinus Torvalds /* resume the processing of a keyring higher up in the tree */ 4251da177e4SLinus Torvalds sp--; 42676d8aeabSDavid Howells keylist = stack[sp].keylist; 4271da177e4SLinus Torvalds kix = stack[sp].kix + 1; 4281da177e4SLinus Torvalds goto ascend; 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 431664cceb0SDavid Howells key_ref = ERR_PTR(err); 432664cceb0SDavid Howells goto error_2; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds /* we found a viable match */ 4351da177e4SLinus Torvalds found: 4361da177e4SLinus Torvalds atomic_inc(&key->usage); 4371da177e4SLinus Torvalds key_check(key); 438664cceb0SDavid Howells key_ref = make_key_ref(key, possessed); 439664cceb0SDavid Howells error_2: 44076d8aeabSDavid Howells rcu_read_unlock(); 441664cceb0SDavid Howells error: 442664cceb0SDavid Howells return key_ref; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds } /* end keyring_search_aux() */ 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds /*****************************************************************************/ 4471da177e4SLinus Torvalds /* 4481da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 4491da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 4501da177e4SLinus Torvalds * - we only find keys on which we have search permission 4511da177e4SLinus Torvalds * - we readlock the keyrings as we search down the tree 4521da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 4531da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 4541da177e4SLinus Torvalds */ 455664cceb0SDavid Howells key_ref_t keyring_search(key_ref_t keyring, 4561da177e4SLinus Torvalds struct key_type *type, 4571da177e4SLinus Torvalds const char *description) 4581da177e4SLinus Torvalds { 4593e30148cSDavid Howells if (!type->match) 4603e30148cSDavid Howells return ERR_PTR(-ENOKEY); 4613e30148cSDavid Howells 462d84f4f99SDavid Howells return keyring_search_aux(keyring, current->cred, 4633e30148cSDavid Howells type, description, type->match); 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds } /* end keyring_search() */ 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_search); 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds /*****************************************************************************/ 4701da177e4SLinus Torvalds /* 4711da177e4SLinus Torvalds * search the given keyring only (no recursion) 4721da177e4SLinus Torvalds * - keyring must be locked by caller 473c3a9d654SDavid Howells * - caller must guarantee that the keyring is a keyring 4741da177e4SLinus Torvalds */ 475664cceb0SDavid Howells key_ref_t __keyring_search_one(key_ref_t keyring_ref, 4761da177e4SLinus Torvalds const struct key_type *ktype, 4771da177e4SLinus Torvalds const char *description, 4781da177e4SLinus Torvalds key_perm_t perm) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds struct keyring_list *klist; 481664cceb0SDavid Howells unsigned long possessed; 482664cceb0SDavid Howells struct key *keyring, *key; 4831da177e4SLinus Torvalds int loop; 4841da177e4SLinus Torvalds 485664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 486664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 487664cceb0SDavid Howells 48876d8aeabSDavid Howells rcu_read_lock(); 48976d8aeabSDavid Howells 49076d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 4911da177e4SLinus Torvalds if (klist) { 4921da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 4931da177e4SLinus Torvalds key = klist->keys[loop]; 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds if (key->type == ktype && 4963e30148cSDavid Howells (!key->type->match || 4973e30148cSDavid Howells key->type->match(key, description)) && 498664cceb0SDavid Howells key_permission(make_key_ref(key, possessed), 499db1d1d57SDavid Howells perm) == 0 && 50076d8aeabSDavid Howells !test_bit(KEY_FLAG_REVOKED, &key->flags) 5011da177e4SLinus Torvalds ) 5021da177e4SLinus Torvalds goto found; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds 506664cceb0SDavid Howells rcu_read_unlock(); 507664cceb0SDavid Howells return ERR_PTR(-ENOKEY); 5081da177e4SLinus Torvalds 5091da177e4SLinus Torvalds found: 5101da177e4SLinus Torvalds atomic_inc(&key->usage); 51176d8aeabSDavid Howells rcu_read_unlock(); 512664cceb0SDavid Howells return make_key_ref(key, possessed); 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds } /* end __keyring_search_one() */ 5151da177e4SLinus Torvalds 5161da177e4SLinus Torvalds /*****************************************************************************/ 5171da177e4SLinus Torvalds /* 5181da177e4SLinus Torvalds * find a keyring with the specified name 5191da177e4SLinus Torvalds * - all named keyrings are searched 52069664cf1SDavid Howells * - normally only finds keyrings with search permission for the current process 5211da177e4SLinus Torvalds */ 52269664cf1SDavid Howells struct key *find_keyring_by_name(const char *name, bool skip_perm_check) 5231da177e4SLinus Torvalds { 5241da177e4SLinus Torvalds struct key *keyring; 5251da177e4SLinus Torvalds int bucket; 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds keyring = ERR_PTR(-EINVAL); 5281da177e4SLinus Torvalds if (!name) 5291da177e4SLinus Torvalds goto error; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds bucket = keyring_hash(name); 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds read_lock(&keyring_name_lock); 5341da177e4SLinus Torvalds 5351da177e4SLinus Torvalds if (keyring_name_hash[bucket].next) { 5361da177e4SLinus Torvalds /* search this hash bucket for a keyring with a matching name 5371da177e4SLinus Torvalds * that's readable and that hasn't been revoked */ 5381da177e4SLinus Torvalds list_for_each_entry(keyring, 5391da177e4SLinus Torvalds &keyring_name_hash[bucket], 5401da177e4SLinus Torvalds type_data.link 5411da177e4SLinus Torvalds ) { 5422ea190d0SSerge E. Hallyn if (keyring->user->user_ns != current_user_ns()) 5432ea190d0SSerge E. Hallyn continue; 5442ea190d0SSerge E. Hallyn 54576d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 5461da177e4SLinus Torvalds continue; 5471da177e4SLinus Torvalds 5481da177e4SLinus Torvalds if (strcmp(keyring->description, name) != 0) 5491da177e4SLinus Torvalds continue; 5501da177e4SLinus Torvalds 55169664cf1SDavid Howells if (!skip_perm_check && 55269664cf1SDavid Howells key_permission(make_key_ref(keyring, 0), 55329db9190SDavid Howells KEY_SEARCH) < 0) 5541da177e4SLinus Torvalds continue; 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds /* we've got a match */ 5571da177e4SLinus Torvalds atomic_inc(&keyring->usage); 5581da177e4SLinus Torvalds read_unlock(&keyring_name_lock); 5591da177e4SLinus Torvalds goto error; 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds read_unlock(&keyring_name_lock); 5641da177e4SLinus Torvalds keyring = ERR_PTR(-ENOKEY); 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds error: 5671da177e4SLinus Torvalds return keyring; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds } /* end find_keyring_by_name() */ 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds /*****************************************************************************/ 5721da177e4SLinus Torvalds /* 5731da177e4SLinus Torvalds * see if a cycle will will be created by inserting acyclic tree B in acyclic 5741da177e4SLinus Torvalds * tree A at the topmost level (ie: as a direct child of A) 5751da177e4SLinus Torvalds * - since we are adding B to A at the top level, checking for cycles should 5761da177e4SLinus Torvalds * just be a matter of seeing if node A is somewhere in tree B 5771da177e4SLinus Torvalds */ 5781da177e4SLinus Torvalds static int keyring_detect_cycle(struct key *A, struct key *B) 5791da177e4SLinus Torvalds { 5801da177e4SLinus Torvalds struct { 58176d8aeabSDavid Howells struct keyring_list *keylist; 5821da177e4SLinus Torvalds int kix; 5831da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds struct keyring_list *keylist; 5861da177e4SLinus Torvalds struct key *subtree, *key; 5871da177e4SLinus Torvalds int sp, kix, ret; 5881da177e4SLinus Torvalds 58976d8aeabSDavid Howells rcu_read_lock(); 59076d8aeabSDavid Howells 5911da177e4SLinus Torvalds ret = -EDEADLK; 5921da177e4SLinus Torvalds if (A == B) 59376d8aeabSDavid Howells goto cycle_detected; 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds subtree = B; 5961da177e4SLinus Torvalds sp = 0; 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds /* start processing a new keyring */ 5991da177e4SLinus Torvalds descend: 60076d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) 6011da177e4SLinus Torvalds goto not_this_keyring; 6021da177e4SLinus Torvalds 60376d8aeabSDavid Howells keylist = rcu_dereference(subtree->payload.subscriptions); 6041da177e4SLinus Torvalds if (!keylist) 6051da177e4SLinus Torvalds goto not_this_keyring; 6061da177e4SLinus Torvalds kix = 0; 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds ascend: 6091da177e4SLinus Torvalds /* iterate through the remaining keys in this keyring */ 6101da177e4SLinus Torvalds for (; kix < keylist->nkeys; kix++) { 6111da177e4SLinus Torvalds key = keylist->keys[kix]; 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds if (key == A) 6141da177e4SLinus Torvalds goto cycle_detected; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds /* recursively check nested keyrings */ 6171da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 6181da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 6191da177e4SLinus Torvalds goto too_deep; 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds /* stack the current position */ 62276d8aeabSDavid Howells stack[sp].keylist = keylist; 6231da177e4SLinus Torvalds stack[sp].kix = kix; 6241da177e4SLinus Torvalds sp++; 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds /* begin again with the new keyring */ 6271da177e4SLinus Torvalds subtree = key; 6281da177e4SLinus Torvalds goto descend; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 6331da177e4SLinus Torvalds * matching key */ 6341da177e4SLinus Torvalds not_this_keyring: 6351da177e4SLinus Torvalds if (sp > 0) { 6361da177e4SLinus Torvalds /* resume the checking of a keyring higher up in the tree */ 6371da177e4SLinus Torvalds sp--; 63876d8aeabSDavid Howells keylist = stack[sp].keylist; 6391da177e4SLinus Torvalds kix = stack[sp].kix + 1; 6401da177e4SLinus Torvalds goto ascend; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds ret = 0; /* no cycles detected */ 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds error: 64676d8aeabSDavid Howells rcu_read_unlock(); 6471da177e4SLinus Torvalds return ret; 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds too_deep: 6501da177e4SLinus Torvalds ret = -ELOOP; 65176d8aeabSDavid Howells goto error; 65276d8aeabSDavid Howells 6531da177e4SLinus Torvalds cycle_detected: 6541da177e4SLinus Torvalds ret = -EDEADLK; 6551da177e4SLinus Torvalds goto error; 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds } /* end keyring_detect_cycle() */ 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds /*****************************************************************************/ 6601da177e4SLinus Torvalds /* 66176d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period 66276d8aeabSDavid Howells */ 66376d8aeabSDavid Howells static void keyring_link_rcu_disposal(struct rcu_head *rcu) 66476d8aeabSDavid Howells { 66576d8aeabSDavid Howells struct keyring_list *klist = 66676d8aeabSDavid Howells container_of(rcu, struct keyring_list, rcu); 66776d8aeabSDavid Howells 66876d8aeabSDavid Howells kfree(klist); 66976d8aeabSDavid Howells 67076d8aeabSDavid Howells } /* end keyring_link_rcu_disposal() */ 67176d8aeabSDavid Howells 67276d8aeabSDavid Howells /*****************************************************************************/ 67376d8aeabSDavid Howells /* 674cab8eb59SDavid Howells * dispose of a keyring list after the RCU grace period, freeing the unlinked 675cab8eb59SDavid Howells * key 676cab8eb59SDavid Howells */ 677cab8eb59SDavid Howells static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) 678cab8eb59SDavid Howells { 679cab8eb59SDavid Howells struct keyring_list *klist = 680cab8eb59SDavid Howells container_of(rcu, struct keyring_list, rcu); 681cab8eb59SDavid Howells 682cab8eb59SDavid Howells key_put(klist->keys[klist->delkey]); 683cab8eb59SDavid Howells kfree(klist); 684cab8eb59SDavid Howells 685cab8eb59SDavid Howells } /* end keyring_unlink_rcu_disposal() */ 686cab8eb59SDavid Howells 687cab8eb59SDavid Howells /*****************************************************************************/ 688cab8eb59SDavid Howells /* 6891da177e4SLinus Torvalds * link a key into to a keyring 69076d8aeabSDavid Howells * - must be called with the keyring's semaphore write-locked 691cab8eb59SDavid Howells * - discard already extant link to matching key if there is one 6921da177e4SLinus Torvalds */ 6931da177e4SLinus Torvalds int __key_link(struct key *keyring, struct key *key) 6941da177e4SLinus Torvalds { 6951da177e4SLinus Torvalds struct keyring_list *klist, *nklist; 6961da177e4SLinus Torvalds unsigned max; 6971da177e4SLinus Torvalds size_t size; 698cab8eb59SDavid Howells int loop, ret; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds ret = -EKEYREVOKED; 70176d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 7021da177e4SLinus Torvalds goto error; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds ret = -ENOTDIR; 7051da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 7061da177e4SLinus Torvalds goto error; 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds /* serialise link/link calls to prevent parallel calls causing a 7091da177e4SLinus Torvalds * cycle when applied to two keyring in opposite orders */ 7101da177e4SLinus Torvalds down_write(&keyring_serialise_link_sem); 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds /* check that we aren't going to create a cycle adding one keyring to 7131da177e4SLinus Torvalds * another */ 7141da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 7151da177e4SLinus Torvalds ret = keyring_detect_cycle(keyring, key); 7161da177e4SLinus Torvalds if (ret < 0) 7171da177e4SLinus Torvalds goto error2; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds 720cab8eb59SDavid Howells /* see if there's a matching key we can displace */ 721cab8eb59SDavid Howells klist = keyring->payload.subscriptions; 722cab8eb59SDavid Howells 723cab8eb59SDavid Howells if (klist && klist->nkeys > 0) { 724cab8eb59SDavid Howells struct key_type *type = key->type; 725cab8eb59SDavid Howells 726cab8eb59SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 727cab8eb59SDavid Howells if (klist->keys[loop]->type == type && 728cab8eb59SDavid Howells strcmp(klist->keys[loop]->description, 729cab8eb59SDavid Howells key->description) == 0 730cab8eb59SDavid Howells ) { 731cab8eb59SDavid Howells /* found a match - replace with new key */ 732cab8eb59SDavid Howells size = sizeof(struct key *) * klist->maxkeys; 733cab8eb59SDavid Howells size += sizeof(*klist); 734cab8eb59SDavid Howells BUG_ON(size > PAGE_SIZE); 735cab8eb59SDavid Howells 736cab8eb59SDavid Howells ret = -ENOMEM; 73748ad504eSEric Sesterhenn nklist = kmemdup(klist, size, GFP_KERNEL); 738cab8eb59SDavid Howells if (!nklist) 739cab8eb59SDavid Howells goto error2; 740cab8eb59SDavid Howells 741cab8eb59SDavid Howells /* replace matched key */ 742cab8eb59SDavid Howells atomic_inc(&key->usage); 743cab8eb59SDavid Howells nklist->keys[loop] = key; 744cab8eb59SDavid Howells 745cab8eb59SDavid Howells rcu_assign_pointer( 746cab8eb59SDavid Howells keyring->payload.subscriptions, 747cab8eb59SDavid Howells nklist); 748cab8eb59SDavid Howells 749cab8eb59SDavid Howells /* dispose of the old keyring list and the 750cab8eb59SDavid Howells * displaced key */ 751cab8eb59SDavid Howells klist->delkey = loop; 752cab8eb59SDavid Howells call_rcu(&klist->rcu, 753cab8eb59SDavid Howells keyring_unlink_rcu_disposal); 754cab8eb59SDavid Howells 755cab8eb59SDavid Howells goto done; 756cab8eb59SDavid Howells } 757cab8eb59SDavid Howells } 758cab8eb59SDavid Howells } 759cab8eb59SDavid Howells 7601da177e4SLinus Torvalds /* check that we aren't going to overrun the user's quota */ 7611da177e4SLinus Torvalds ret = key_payload_reserve(keyring, 7621da177e4SLinus Torvalds keyring->datalen + KEYQUOTA_LINK_BYTES); 7631da177e4SLinus Torvalds if (ret < 0) 7641da177e4SLinus Torvalds goto error2; 7651da177e4SLinus Torvalds 7661da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds if (klist && klist->nkeys < klist->maxkeys) { 7691da177e4SLinus Torvalds /* there's sufficient slack space to add directly */ 7701da177e4SLinus Torvalds atomic_inc(&key->usage); 7711da177e4SLinus Torvalds 77276d8aeabSDavid Howells klist->keys[klist->nkeys] = key; 77376d8aeabSDavid Howells smp_wmb(); 77476d8aeabSDavid Howells klist->nkeys++; 77576d8aeabSDavid Howells smp_wmb(); 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds else { 7781da177e4SLinus Torvalds /* grow the key list */ 7791da177e4SLinus Torvalds max = 4; 7801da177e4SLinus Torvalds if (klist) 7811da177e4SLinus Torvalds max += klist->maxkeys; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds ret = -ENFILE; 78476d8aeabSDavid Howells if (max > 65535) 78576d8aeabSDavid Howells goto error3; 786a4014d8fSDavid Howells size = sizeof(*klist) + sizeof(struct key *) * max; 7871da177e4SLinus Torvalds if (size > PAGE_SIZE) 7881da177e4SLinus Torvalds goto error3; 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds ret = -ENOMEM; 7911da177e4SLinus Torvalds nklist = kmalloc(size, GFP_KERNEL); 7921da177e4SLinus Torvalds if (!nklist) 7931da177e4SLinus Torvalds goto error3; 7941da177e4SLinus Torvalds nklist->maxkeys = max; 7951da177e4SLinus Torvalds nklist->nkeys = 0; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds if (klist) { 7981da177e4SLinus Torvalds nklist->nkeys = klist->nkeys; 7991da177e4SLinus Torvalds memcpy(nklist->keys, 8001da177e4SLinus Torvalds klist->keys, 8011da177e4SLinus Torvalds sizeof(struct key *) * klist->nkeys); 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds /* add the key into the new space */ 8051da177e4SLinus Torvalds atomic_inc(&key->usage); 8061da177e4SLinus Torvalds nklist->keys[nklist->nkeys++] = key; 80776d8aeabSDavid Howells 80876d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds /* dispose of the old keyring list */ 81176d8aeabSDavid Howells if (klist) 81276d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_link_rcu_disposal); 8131da177e4SLinus Torvalds } 8141da177e4SLinus Torvalds 815cab8eb59SDavid Howells done: 816cab8eb59SDavid Howells ret = 0; 8171da177e4SLinus Torvalds error2: 8181da177e4SLinus Torvalds up_write(&keyring_serialise_link_sem); 8191da177e4SLinus Torvalds error: 8201da177e4SLinus Torvalds return ret; 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds error3: 8231da177e4SLinus Torvalds /* undo the quota changes */ 8241da177e4SLinus Torvalds key_payload_reserve(keyring, 8251da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 8261da177e4SLinus Torvalds goto error2; 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds } /* end __key_link() */ 8291da177e4SLinus Torvalds 8301da177e4SLinus Torvalds /*****************************************************************************/ 8311da177e4SLinus Torvalds /* 8321da177e4SLinus Torvalds * link a key to a keyring 8331da177e4SLinus Torvalds */ 8341da177e4SLinus Torvalds int key_link(struct key *keyring, struct key *key) 8351da177e4SLinus Torvalds { 8361da177e4SLinus Torvalds int ret; 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds key_check(keyring); 8391da177e4SLinus Torvalds key_check(key); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds down_write(&keyring->sem); 8421da177e4SLinus Torvalds ret = __key_link(keyring, key); 8431da177e4SLinus Torvalds up_write(&keyring->sem); 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds return ret; 8461da177e4SLinus Torvalds 8471da177e4SLinus Torvalds } /* end key_link() */ 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds EXPORT_SYMBOL(key_link); 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds /*****************************************************************************/ 8521da177e4SLinus Torvalds /* 8531da177e4SLinus Torvalds * unlink the first link to a key from a keyring 8541da177e4SLinus Torvalds */ 8551da177e4SLinus Torvalds int key_unlink(struct key *keyring, struct key *key) 8561da177e4SLinus Torvalds { 85776d8aeabSDavid Howells struct keyring_list *klist, *nklist; 8581da177e4SLinus Torvalds int loop, ret; 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds key_check(keyring); 8611da177e4SLinus Torvalds key_check(key); 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds ret = -ENOTDIR; 8641da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 8651da177e4SLinus Torvalds goto error; 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds down_write(&keyring->sem); 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 8701da177e4SLinus Torvalds if (klist) { 8711da177e4SLinus Torvalds /* search the keyring for the key */ 8721da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) 8731da177e4SLinus Torvalds if (klist->keys[loop] == key) 8741da177e4SLinus Torvalds goto key_is_present; 8751da177e4SLinus Torvalds } 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds up_write(&keyring->sem); 8781da177e4SLinus Torvalds ret = -ENOENT; 8791da177e4SLinus Torvalds goto error; 8801da177e4SLinus Torvalds 8811da177e4SLinus Torvalds key_is_present: 88276d8aeabSDavid Howells /* we need to copy the key list for RCU purposes */ 883a4014d8fSDavid Howells nklist = kmalloc(sizeof(*klist) + 884a4014d8fSDavid Howells sizeof(struct key *) * klist->maxkeys, 88576d8aeabSDavid Howells GFP_KERNEL); 88676d8aeabSDavid Howells if (!nklist) 88776d8aeabSDavid Howells goto nomem; 88876d8aeabSDavid Howells nklist->maxkeys = klist->maxkeys; 88976d8aeabSDavid Howells nklist->nkeys = klist->nkeys - 1; 89076d8aeabSDavid Howells 89176d8aeabSDavid Howells if (loop > 0) 89276d8aeabSDavid Howells memcpy(&nklist->keys[0], 89376d8aeabSDavid Howells &klist->keys[0], 894a4014d8fSDavid Howells loop * sizeof(struct key *)); 89576d8aeabSDavid Howells 89676d8aeabSDavid Howells if (loop < nklist->nkeys) 89776d8aeabSDavid Howells memcpy(&nklist->keys[loop], 89876d8aeabSDavid Howells &klist->keys[loop + 1], 899a4014d8fSDavid Howells (nklist->nkeys - loop) * sizeof(struct key *)); 90076d8aeabSDavid Howells 9011da177e4SLinus Torvalds /* adjust the user's quota */ 9021da177e4SLinus Torvalds key_payload_reserve(keyring, 9031da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 9041da177e4SLinus Torvalds 90576d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds up_write(&keyring->sem); 90876d8aeabSDavid Howells 90976d8aeabSDavid Howells /* schedule for later cleanup */ 91076d8aeabSDavid Howells klist->delkey = loop; 91176d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 91276d8aeabSDavid Howells 9131da177e4SLinus Torvalds ret = 0; 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds error: 9161da177e4SLinus Torvalds return ret; 91776d8aeabSDavid Howells nomem: 91876d8aeabSDavid Howells ret = -ENOMEM; 91976d8aeabSDavid Howells up_write(&keyring->sem); 92076d8aeabSDavid Howells goto error; 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds } /* end key_unlink() */ 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds EXPORT_SYMBOL(key_unlink); 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds /*****************************************************************************/ 9271da177e4SLinus Torvalds /* 92876d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period, releasing the keys it 92976d8aeabSDavid Howells * links to 93076d8aeabSDavid Howells */ 93176d8aeabSDavid Howells static void keyring_clear_rcu_disposal(struct rcu_head *rcu) 93276d8aeabSDavid Howells { 93376d8aeabSDavid Howells struct keyring_list *klist; 93476d8aeabSDavid Howells int loop; 93576d8aeabSDavid Howells 93676d8aeabSDavid Howells klist = container_of(rcu, struct keyring_list, rcu); 93776d8aeabSDavid Howells 93876d8aeabSDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 93976d8aeabSDavid Howells key_put(klist->keys[loop]); 94076d8aeabSDavid Howells 94176d8aeabSDavid Howells kfree(klist); 94276d8aeabSDavid Howells 94376d8aeabSDavid Howells } /* end keyring_clear_rcu_disposal() */ 94476d8aeabSDavid Howells 94576d8aeabSDavid Howells /*****************************************************************************/ 94676d8aeabSDavid Howells /* 9471da177e4SLinus Torvalds * clear the specified process keyring 9481da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CLEAR) 9491da177e4SLinus Torvalds */ 9501da177e4SLinus Torvalds int keyring_clear(struct key *keyring) 9511da177e4SLinus Torvalds { 9521da177e4SLinus Torvalds struct keyring_list *klist; 95376d8aeabSDavid Howells int ret; 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds ret = -ENOTDIR; 9561da177e4SLinus Torvalds if (keyring->type == &key_type_keyring) { 9571da177e4SLinus Torvalds /* detach the pointer block with the locks held */ 9581da177e4SLinus Torvalds down_write(&keyring->sem); 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 9611da177e4SLinus Torvalds if (klist) { 9621da177e4SLinus Torvalds /* adjust the quota */ 9631da177e4SLinus Torvalds key_payload_reserve(keyring, 9641da177e4SLinus Torvalds sizeof(struct keyring_list)); 9651da177e4SLinus Torvalds 96676d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, 96776d8aeabSDavid Howells NULL); 9681da177e4SLinus Torvalds } 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds up_write(&keyring->sem); 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds /* free the keys after the locks have been dropped */ 97376d8aeabSDavid Howells if (klist) 97476d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds ret = 0; 9771da177e4SLinus Torvalds } 9781da177e4SLinus Torvalds 9791da177e4SLinus Torvalds return ret; 9801da177e4SLinus Torvalds 9811da177e4SLinus Torvalds } /* end keyring_clear() */ 9821da177e4SLinus Torvalds 9831da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_clear); 98431204ed9SDavid Howells 98531204ed9SDavid Howells /*****************************************************************************/ 98631204ed9SDavid Howells /* 98731204ed9SDavid Howells * dispose of the links from a revoked keyring 98831204ed9SDavid Howells * - called with the key sem write-locked 98931204ed9SDavid Howells */ 99031204ed9SDavid Howells static void keyring_revoke(struct key *keyring) 99131204ed9SDavid Howells { 99231204ed9SDavid Howells struct keyring_list *klist = keyring->payload.subscriptions; 99331204ed9SDavid Howells 99431204ed9SDavid Howells /* adjust the quota */ 99531204ed9SDavid Howells key_payload_reserve(keyring, 0); 99631204ed9SDavid Howells 99731204ed9SDavid Howells if (klist) { 99831204ed9SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, NULL); 99931204ed9SDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 100031204ed9SDavid Howells } 100131204ed9SDavid Howells 100231204ed9SDavid Howells } /* end keyring_revoke() */ 10035d135440SDavid Howells 10045d135440SDavid Howells /* 10055d135440SDavid Howells * Determine whether a key is dead 10065d135440SDavid Howells */ 10075d135440SDavid Howells static bool key_is_dead(struct key *key, time_t limit) 10085d135440SDavid Howells { 10095d135440SDavid Howells return test_bit(KEY_FLAG_DEAD, &key->flags) || 10105d135440SDavid Howells (key->expiry > 0 && key->expiry <= limit); 10115d135440SDavid Howells } 10125d135440SDavid Howells 10135d135440SDavid Howells /* 10145d135440SDavid Howells * Collect garbage from the contents of a keyring 10155d135440SDavid Howells */ 10165d135440SDavid Howells void keyring_gc(struct key *keyring, time_t limit) 10175d135440SDavid Howells { 10185d135440SDavid Howells struct keyring_list *klist, *new; 10195d135440SDavid Howells struct key *key; 10205d135440SDavid Howells int loop, keep, max; 10215d135440SDavid Howells 1022c08ef808SDavid Howells kenter("{%x,%s}", key_serial(keyring), keyring->description); 10235d135440SDavid Howells 10245d135440SDavid Howells down_write(&keyring->sem); 10255d135440SDavid Howells 10265d135440SDavid Howells klist = keyring->payload.subscriptions; 10275d135440SDavid Howells if (!klist) 1028c08ef808SDavid Howells goto no_klist; 10295d135440SDavid Howells 10305d135440SDavid Howells /* work out how many subscriptions we're keeping */ 10315d135440SDavid Howells keep = 0; 10325d135440SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 1033c08ef808SDavid Howells if (!key_is_dead(klist->keys[loop], limit)) 10345d135440SDavid Howells keep++; 10355d135440SDavid Howells 10365d135440SDavid Howells if (keep == klist->nkeys) 10375d135440SDavid Howells goto just_return; 10385d135440SDavid Howells 10395d135440SDavid Howells /* allocate a new keyring payload */ 10405d135440SDavid Howells max = roundup(keep, 4); 10415d135440SDavid Howells new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), 10425d135440SDavid Howells GFP_KERNEL); 10435d135440SDavid Howells if (!new) 1044c08ef808SDavid Howells goto nomem; 10455d135440SDavid Howells new->maxkeys = max; 10465d135440SDavid Howells new->nkeys = 0; 10475d135440SDavid Howells new->delkey = 0; 10485d135440SDavid Howells 10495d135440SDavid Howells /* install the live keys 10505d135440SDavid Howells * - must take care as expired keys may be updated back to life 10515d135440SDavid Howells */ 10525d135440SDavid Howells keep = 0; 10535d135440SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 10545d135440SDavid Howells key = klist->keys[loop]; 10555d135440SDavid Howells if (!key_is_dead(key, limit)) { 10565d135440SDavid Howells if (keep >= max) 10575d135440SDavid Howells goto discard_new; 10585d135440SDavid Howells new->keys[keep++] = key_get(key); 10595d135440SDavid Howells } 10605d135440SDavid Howells } 10615d135440SDavid Howells new->nkeys = keep; 10625d135440SDavid Howells 10635d135440SDavid Howells /* adjust the quota */ 10645d135440SDavid Howells key_payload_reserve(keyring, 10655d135440SDavid Howells sizeof(struct keyring_list) + 10665d135440SDavid Howells KEYQUOTA_LINK_BYTES * keep); 10675d135440SDavid Howells 10685d135440SDavid Howells if (keep == 0) { 10695d135440SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, NULL); 10705d135440SDavid Howells kfree(new); 10715d135440SDavid Howells } else { 10725d135440SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, new); 10735d135440SDavid Howells } 10745d135440SDavid Howells 10755d135440SDavid Howells up_write(&keyring->sem); 10765d135440SDavid Howells 10775d135440SDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 10785d135440SDavid Howells kleave(" [yes]"); 10795d135440SDavid Howells return; 10805d135440SDavid Howells 10815d135440SDavid Howells discard_new: 10825d135440SDavid Howells new->nkeys = keep; 10835d135440SDavid Howells keyring_clear_rcu_disposal(&new->rcu); 1084c08ef808SDavid Howells up_write(&keyring->sem); 1085c08ef808SDavid Howells kleave(" [discard]"); 1086c08ef808SDavid Howells return; 1087c08ef808SDavid Howells 10885d135440SDavid Howells just_return: 10895d135440SDavid Howells up_write(&keyring->sem); 1090c08ef808SDavid Howells kleave(" [no dead]"); 1091c08ef808SDavid Howells return; 1092c08ef808SDavid Howells 1093c08ef808SDavid Howells no_klist: 1094c08ef808SDavid Howells up_write(&keyring->sem); 1095c08ef808SDavid Howells kleave(" [no_klist]"); 1096c08ef808SDavid Howells return; 1097c08ef808SDavid Howells 1098c08ef808SDavid Howells nomem: 1099c08ef808SDavid Howells up_write(&keyring->sem); 1100c08ef808SDavid Howells kleave(" [oom]"); 11015d135440SDavid Howells } 1102