11da177e4SLinus Torvalds /* keyring.c: keyring handling 21da177e4SLinus Torvalds * 33e30148cSDavid Howells * Copyright (C) 2004-5 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> 161da177e4SLinus Torvalds #include <linux/seq_file.h> 171da177e4SLinus Torvalds #include <linux/err.h> 181da177e4SLinus Torvalds #include <asm/uaccess.h> 191da177e4SLinus Torvalds #include "internal.h" 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds /* 221da177e4SLinus Torvalds * when plumbing the depths of the key tree, this sets a hard limit set on how 231da177e4SLinus Torvalds * deep we're willing to go 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds #define KEYRING_SEARCH_MAX_DEPTH 6 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 281da177e4SLinus Torvalds * we keep all named keyrings in a hash to speed looking them up 291da177e4SLinus Torvalds */ 301da177e4SLinus Torvalds #define KEYRING_NAME_HASH_SIZE (1 << 5) 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; 331da177e4SLinus Torvalds static DEFINE_RWLOCK(keyring_name_lock); 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static inline unsigned keyring_hash(const char *desc) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds unsigned bucket = 0; 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds for (; *desc; desc++) 401da177e4SLinus Torvalds bucket += (unsigned char) *desc; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds return bucket & (KEYRING_NAME_HASH_SIZE - 1); 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds /* 461da177e4SLinus Torvalds * the keyring type definition 471da177e4SLinus Torvalds */ 481da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 491da177e4SLinus Torvalds const void *data, size_t datalen); 501da177e4SLinus Torvalds static int keyring_duplicate(struct key *keyring, const struct key *source); 511da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *criterion); 521da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring); 531da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m); 541da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 551da177e4SLinus Torvalds char __user *buffer, size_t buflen); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds struct key_type key_type_keyring = { 581da177e4SLinus Torvalds .name = "keyring", 591da177e4SLinus Torvalds .def_datalen = sizeof(struct keyring_list), 601da177e4SLinus Torvalds .instantiate = keyring_instantiate, 611da177e4SLinus Torvalds .duplicate = keyring_duplicate, 621da177e4SLinus Torvalds .match = keyring_match, 631da177e4SLinus Torvalds .destroy = keyring_destroy, 641da177e4SLinus Torvalds .describe = keyring_describe, 651da177e4SLinus Torvalds .read = keyring_read, 661da177e4SLinus Torvalds }; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds /* 691da177e4SLinus Torvalds * semaphore to serialise link/link calls to prevent two link calls in parallel 701da177e4SLinus Torvalds * introducing a cycle 711da177e4SLinus Torvalds */ 721da177e4SLinus Torvalds DECLARE_RWSEM(keyring_serialise_link_sem); 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds /*****************************************************************************/ 751da177e4SLinus Torvalds /* 761da177e4SLinus Torvalds * publish the name of a keyring so that it can be found by name (if it has 771da177e4SLinus Torvalds * one) 781da177e4SLinus Torvalds */ 791da177e4SLinus Torvalds void keyring_publish_name(struct key *keyring) 801da177e4SLinus Torvalds { 811da177e4SLinus Torvalds int bucket; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds if (keyring->description) { 841da177e4SLinus Torvalds bucket = keyring_hash(keyring->description); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds write_lock(&keyring_name_lock); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds if (!keyring_name_hash[bucket].next) 891da177e4SLinus Torvalds INIT_LIST_HEAD(&keyring_name_hash[bucket]); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds list_add_tail(&keyring->type_data.link, 921da177e4SLinus Torvalds &keyring_name_hash[bucket]); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds } /* end keyring_publish_name() */ 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds /*****************************************************************************/ 1001da177e4SLinus Torvalds /* 1011da177e4SLinus Torvalds * initialise a keyring 1021da177e4SLinus Torvalds * - we object if we were given any data 1031da177e4SLinus Torvalds */ 1041da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 1051da177e4SLinus Torvalds const void *data, size_t datalen) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds int ret; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds ret = -EINVAL; 1101da177e4SLinus Torvalds if (datalen == 0) { 1111da177e4SLinus Torvalds /* make the keyring available by name if it has one */ 1121da177e4SLinus Torvalds keyring_publish_name(keyring); 1131da177e4SLinus Torvalds ret = 0; 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds return ret; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds } /* end keyring_instantiate() */ 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds /*****************************************************************************/ 1211da177e4SLinus Torvalds /* 1221da177e4SLinus Torvalds * duplicate the list of subscribed keys from a source keyring into this one 1231da177e4SLinus Torvalds */ 1241da177e4SLinus Torvalds static int keyring_duplicate(struct key *keyring, const struct key *source) 1251da177e4SLinus Torvalds { 1261da177e4SLinus Torvalds struct keyring_list *sklist, *klist; 1271da177e4SLinus Torvalds unsigned max; 1281da177e4SLinus Torvalds size_t size; 1291da177e4SLinus Torvalds int loop, ret; 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds const unsigned limit = 132a4014d8fSDavid Howells (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key *); 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds ret = 0; 1351da177e4SLinus Torvalds 13676d8aeabSDavid Howells /* find out how many keys are currently linked */ 13776d8aeabSDavid Howells rcu_read_lock(); 13876d8aeabSDavid Howells sklist = rcu_dereference(source->payload.subscriptions); 13976d8aeabSDavid Howells max = 0; 14076d8aeabSDavid Howells if (sklist) 1411da177e4SLinus Torvalds max = sklist->nkeys; 14276d8aeabSDavid Howells rcu_read_unlock(); 14376d8aeabSDavid Howells 14476d8aeabSDavid Howells /* allocate a new payload and stuff load with key links */ 14576d8aeabSDavid Howells if (max > 0) { 1461da177e4SLinus Torvalds BUG_ON(max > limit); 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds max = (max + 3) & ~3; 1491da177e4SLinus Torvalds if (max > limit) 1501da177e4SLinus Torvalds max = limit; 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds ret = -ENOMEM; 153a4014d8fSDavid Howells size = sizeof(*klist) + sizeof(struct key *) * max; 1541da177e4SLinus Torvalds klist = kmalloc(size, GFP_KERNEL); 1551da177e4SLinus Torvalds if (!klist) 1561da177e4SLinus Torvalds goto error; 1571da177e4SLinus Torvalds 15876d8aeabSDavid Howells /* set links */ 15976d8aeabSDavid Howells rcu_read_lock(); 16076d8aeabSDavid Howells sklist = rcu_dereference(source->payload.subscriptions); 16176d8aeabSDavid Howells 1621da177e4SLinus Torvalds klist->maxkeys = max; 1631da177e4SLinus Torvalds klist->nkeys = sklist->nkeys; 1641da177e4SLinus Torvalds memcpy(klist->keys, 1651da177e4SLinus Torvalds sklist->keys, 166a4014d8fSDavid Howells sklist->nkeys * sizeof(struct key *)); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds for (loop = klist->nkeys - 1; loop >= 0; loop--) 1691da177e4SLinus Torvalds atomic_inc(&klist->keys[loop]->usage); 1701da177e4SLinus Torvalds 17176d8aeabSDavid Howells rcu_read_unlock(); 17276d8aeabSDavid Howells 17376d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, klist); 1741da177e4SLinus Torvalds ret = 0; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds error: 1781da177e4SLinus Torvalds return ret; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds } /* end keyring_duplicate() */ 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds /*****************************************************************************/ 1831da177e4SLinus Torvalds /* 1841da177e4SLinus Torvalds * match keyrings on their name 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *description) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds return keyring->description && 1891da177e4SLinus Torvalds strcmp(keyring->description, description) == 0; 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds } /* end keyring_match() */ 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds /*****************************************************************************/ 1941da177e4SLinus Torvalds /* 1951da177e4SLinus Torvalds * dispose of the data dangling from the corpse of a keyring 1961da177e4SLinus Torvalds */ 1971da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds struct keyring_list *klist; 2001da177e4SLinus Torvalds int loop; 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds if (keyring->description) { 2031da177e4SLinus Torvalds write_lock(&keyring_name_lock); 20494efe72fSDavid Howells 20594efe72fSDavid Howells if (keyring->type_data.link.next != NULL && 20694efe72fSDavid Howells !list_empty(&keyring->type_data.link)) 2071da177e4SLinus Torvalds list_del(&keyring->type_data.link); 20894efe72fSDavid Howells 2091da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 21276d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 2131da177e4SLinus Torvalds if (klist) { 2141da177e4SLinus Torvalds for (loop = klist->nkeys - 1; loop >= 0; loop--) 2151da177e4SLinus Torvalds key_put(klist->keys[loop]); 2161da177e4SLinus Torvalds kfree(klist); 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds } /* end keyring_destroy() */ 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /*****************************************************************************/ 2221da177e4SLinus Torvalds /* 2231da177e4SLinus Torvalds * describe the keyring 2241da177e4SLinus Torvalds */ 2251da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds struct keyring_list *klist; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds if (keyring->description) { 2301da177e4SLinus Torvalds seq_puts(m, keyring->description); 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds else { 2331da177e4SLinus Torvalds seq_puts(m, "[anon]"); 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 23676d8aeabSDavid Howells rcu_read_lock(); 23776d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 2381da177e4SLinus Torvalds if (klist) 2391da177e4SLinus Torvalds seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); 2401da177e4SLinus Torvalds else 2411da177e4SLinus Torvalds seq_puts(m, ": empty"); 24276d8aeabSDavid Howells rcu_read_unlock(); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds } /* end keyring_describe() */ 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds /*****************************************************************************/ 2471da177e4SLinus Torvalds /* 2481da177e4SLinus Torvalds * read a list of key IDs from the keyring's contents 24976d8aeabSDavid Howells * - the keyring's semaphore is read-locked 2501da177e4SLinus Torvalds */ 2511da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 2521da177e4SLinus Torvalds char __user *buffer, size_t buflen) 2531da177e4SLinus Torvalds { 2541da177e4SLinus Torvalds struct keyring_list *klist; 2551da177e4SLinus Torvalds struct key *key; 2561da177e4SLinus Torvalds size_t qty, tmp; 2571da177e4SLinus Torvalds int loop, ret; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds ret = 0; 26076d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds if (klist) { 2631da177e4SLinus Torvalds /* calculate how much data we could return */ 2641da177e4SLinus Torvalds qty = klist->nkeys * sizeof(key_serial_t); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds if (buffer && buflen > 0) { 2671da177e4SLinus Torvalds if (buflen > qty) 2681da177e4SLinus Torvalds buflen = qty; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds /* copy the IDs of the subscribed keys into the 2711da177e4SLinus Torvalds * buffer */ 2721da177e4SLinus Torvalds ret = -EFAULT; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 2751da177e4SLinus Torvalds key = klist->keys[loop]; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds tmp = sizeof(key_serial_t); 2781da177e4SLinus Torvalds if (tmp > buflen) 2791da177e4SLinus Torvalds tmp = buflen; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds if (copy_to_user(buffer, 2821da177e4SLinus Torvalds &key->serial, 2831da177e4SLinus Torvalds tmp) != 0) 2841da177e4SLinus Torvalds goto error; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds buflen -= tmp; 2871da177e4SLinus Torvalds if (buflen == 0) 2881da177e4SLinus Torvalds break; 2891da177e4SLinus Torvalds buffer += tmp; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds ret = qty; 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds error: 2971da177e4SLinus Torvalds return ret; 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds } /* end keyring_read() */ 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /*****************************************************************************/ 3021da177e4SLinus Torvalds /* 3031da177e4SLinus Torvalds * allocate a keyring and link into the destination keyring 3041da177e4SLinus Torvalds */ 3051da177e4SLinus Torvalds struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, 3061da177e4SLinus Torvalds int not_in_quota, struct key *dest) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds struct key *keyring; 3091da177e4SLinus Torvalds int ret; 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds keyring = key_alloc(&key_type_keyring, description, 312*664cceb0SDavid Howells uid, gid, KEY_POS_ALL | KEY_USR_ALL, not_in_quota); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds if (!IS_ERR(keyring)) { 3153e30148cSDavid Howells ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); 3161da177e4SLinus Torvalds if (ret < 0) { 3171da177e4SLinus Torvalds key_put(keyring); 3181da177e4SLinus Torvalds keyring = ERR_PTR(ret); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds return keyring; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds } /* end keyring_alloc() */ 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds /*****************************************************************************/ 3271da177e4SLinus Torvalds /* 3281da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 3291da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 3301da177e4SLinus Torvalds * - we only find keys on which we have search permission 3311da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 3321da177e4SLinus Torvalds * feature of interest) matches 3333e30148cSDavid Howells * - we rely on RCU to prevent the keyring lists from disappearing on us 3341da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 3351da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 336*664cceb0SDavid Howells * - we propagate the possession attribute from the keyring ref to the key ref 3371da177e4SLinus Torvalds */ 338*664cceb0SDavid Howells key_ref_t keyring_search_aux(key_ref_t keyring_ref, 3393e30148cSDavid Howells struct task_struct *context, 3401da177e4SLinus Torvalds struct key_type *type, 3411da177e4SLinus Torvalds const void *description, 3421da177e4SLinus Torvalds key_match_func_t match) 3431da177e4SLinus Torvalds { 3441da177e4SLinus Torvalds struct { 34576d8aeabSDavid Howells struct keyring_list *keylist; 3461da177e4SLinus Torvalds int kix; 3471da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds struct keyring_list *keylist; 3501da177e4SLinus Torvalds struct timespec now; 351*664cceb0SDavid Howells unsigned long possessed; 352*664cceb0SDavid Howells struct key *keyring, *key; 353*664cceb0SDavid Howells key_ref_t key_ref; 3541da177e4SLinus Torvalds long err; 35576d8aeabSDavid Howells int sp, kix; 3561da177e4SLinus Torvalds 357*664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 358*664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 3591da177e4SLinus Torvalds key_check(keyring); 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds /* top keyring must have search permission to begin the search */ 362*664cceb0SDavid Howells key_ref = ERR_PTR(-EACCES); 363*664cceb0SDavid Howells if (!key_task_permission(keyring_ref, context, KEY_SEARCH)) 3641da177e4SLinus Torvalds goto error; 3651da177e4SLinus Torvalds 366*664cceb0SDavid Howells key_ref = ERR_PTR(-ENOTDIR); 3671da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 3681da177e4SLinus Torvalds goto error; 3691da177e4SLinus Torvalds 370*664cceb0SDavid Howells rcu_read_lock(); 371*664cceb0SDavid Howells 3721da177e4SLinus Torvalds now = current_kernel_time(); 3731da177e4SLinus Torvalds err = -EAGAIN; 3741da177e4SLinus Torvalds sp = 0; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds /* start processing a new keyring */ 3771da177e4SLinus Torvalds descend: 37876d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 3791da177e4SLinus Torvalds goto not_this_keyring; 3801da177e4SLinus Torvalds 38176d8aeabSDavid Howells keylist = rcu_dereference(keyring->payload.subscriptions); 3821da177e4SLinus Torvalds if (!keylist) 3831da177e4SLinus Torvalds goto not_this_keyring; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds /* iterate through the keys in this keyring first */ 3861da177e4SLinus Torvalds for (kix = 0; kix < keylist->nkeys; kix++) { 3871da177e4SLinus Torvalds key = keylist->keys[kix]; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* ignore keys not of this type */ 3901da177e4SLinus Torvalds if (key->type != type) 3911da177e4SLinus Torvalds continue; 3921da177e4SLinus Torvalds 3931da177e4SLinus Torvalds /* skip revoked keys and expired keys */ 39476d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &key->flags)) 3951da177e4SLinus Torvalds continue; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds if (key->expiry && now.tv_sec >= key->expiry) 3981da177e4SLinus Torvalds continue; 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* keys that don't match */ 4011da177e4SLinus Torvalds if (!match(key, description)) 4021da177e4SLinus Torvalds continue; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds /* key must have search permissions */ 405*664cceb0SDavid Howells if (!key_task_permission(make_key_ref(key, possessed), 406*664cceb0SDavid Howells context, KEY_SEARCH)) 4071da177e4SLinus Torvalds continue; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* we set a different error code if we find a negative key */ 41076d8aeabSDavid Howells if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { 4111da177e4SLinus Torvalds err = -ENOKEY; 4121da177e4SLinus Torvalds continue; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds goto found; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds /* search through the keyrings nested in this one */ 4191da177e4SLinus Torvalds kix = 0; 4201da177e4SLinus Torvalds ascend: 42176d8aeabSDavid Howells for (; kix < keylist->nkeys; kix++) { 4221da177e4SLinus Torvalds key = keylist->keys[kix]; 4231da177e4SLinus Torvalds if (key->type != &key_type_keyring) 42476d8aeabSDavid Howells continue; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds /* recursively search nested keyrings 4271da177e4SLinus Torvalds * - only search keyrings for which we have search permission 4281da177e4SLinus Torvalds */ 4291da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 43076d8aeabSDavid Howells continue; 4311da177e4SLinus Torvalds 432*664cceb0SDavid Howells if (!key_task_permission(make_key_ref(key, possessed), 433*664cceb0SDavid Howells context, KEY_SEARCH)) 43476d8aeabSDavid Howells continue; 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds /* stack the current position */ 43776d8aeabSDavid Howells stack[sp].keylist = keylist; 4381da177e4SLinus Torvalds stack[sp].kix = kix; 4391da177e4SLinus Torvalds sp++; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds /* begin again with the new keyring */ 4421da177e4SLinus Torvalds keyring = key; 4431da177e4SLinus Torvalds goto descend; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 4471da177e4SLinus Torvalds * matching key */ 4481da177e4SLinus Torvalds not_this_keyring: 4491da177e4SLinus Torvalds if (sp > 0) { 4501da177e4SLinus Torvalds /* resume the processing of a keyring higher up in the tree */ 4511da177e4SLinus Torvalds sp--; 45276d8aeabSDavid Howells keylist = stack[sp].keylist; 4531da177e4SLinus Torvalds kix = stack[sp].kix + 1; 4541da177e4SLinus Torvalds goto ascend; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 457*664cceb0SDavid Howells key_ref = ERR_PTR(err); 458*664cceb0SDavid Howells goto error_2; 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds /* we found a viable match */ 4611da177e4SLinus Torvalds found: 4621da177e4SLinus Torvalds atomic_inc(&key->usage); 4631da177e4SLinus Torvalds key_check(key); 464*664cceb0SDavid Howells key_ref = make_key_ref(key, possessed); 465*664cceb0SDavid Howells error_2: 46676d8aeabSDavid Howells rcu_read_unlock(); 467*664cceb0SDavid Howells error: 468*664cceb0SDavid Howells return key_ref; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds } /* end keyring_search_aux() */ 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds /*****************************************************************************/ 4731da177e4SLinus Torvalds /* 4741da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 4751da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 4761da177e4SLinus Torvalds * - we only find keys on which we have search permission 4771da177e4SLinus Torvalds * - we readlock the keyrings as we search down the tree 4781da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 4791da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 4801da177e4SLinus Torvalds */ 481*664cceb0SDavid Howells key_ref_t keyring_search(key_ref_t keyring, 4821da177e4SLinus Torvalds struct key_type *type, 4831da177e4SLinus Torvalds const char *description) 4841da177e4SLinus Torvalds { 4853e30148cSDavid Howells if (!type->match) 4863e30148cSDavid Howells return ERR_PTR(-ENOKEY); 4873e30148cSDavid Howells 4883e30148cSDavid Howells return keyring_search_aux(keyring, current, 4893e30148cSDavid Howells type, description, type->match); 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds } /* end keyring_search() */ 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_search); 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds /*****************************************************************************/ 4961da177e4SLinus Torvalds /* 4971da177e4SLinus Torvalds * search the given keyring only (no recursion) 4981da177e4SLinus Torvalds * - keyring must be locked by caller 4991da177e4SLinus Torvalds */ 500*664cceb0SDavid Howells key_ref_t __keyring_search_one(key_ref_t keyring_ref, 5011da177e4SLinus Torvalds const struct key_type *ktype, 5021da177e4SLinus Torvalds const char *description, 5031da177e4SLinus Torvalds key_perm_t perm) 5041da177e4SLinus Torvalds { 5051da177e4SLinus Torvalds struct keyring_list *klist; 506*664cceb0SDavid Howells unsigned long possessed; 507*664cceb0SDavid Howells struct key *keyring, *key; 5081da177e4SLinus Torvalds int loop; 5091da177e4SLinus Torvalds 510*664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 511*664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 512*664cceb0SDavid Howells 51376d8aeabSDavid Howells rcu_read_lock(); 51476d8aeabSDavid Howells 51576d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 5161da177e4SLinus Torvalds if (klist) { 5171da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 5181da177e4SLinus Torvalds key = klist->keys[loop]; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds if (key->type == ktype && 5213e30148cSDavid Howells (!key->type->match || 5223e30148cSDavid Howells key->type->match(key, description)) && 523*664cceb0SDavid Howells key_permission(make_key_ref(key, possessed), 524*664cceb0SDavid Howells perm) && 52576d8aeabSDavid Howells !test_bit(KEY_FLAG_REVOKED, &key->flags) 5261da177e4SLinus Torvalds ) 5271da177e4SLinus Torvalds goto found; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds 531*664cceb0SDavid Howells rcu_read_unlock(); 532*664cceb0SDavid Howells return ERR_PTR(-ENOKEY); 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds found: 5351da177e4SLinus Torvalds atomic_inc(&key->usage); 53676d8aeabSDavid Howells rcu_read_unlock(); 537*664cceb0SDavid Howells return make_key_ref(key, possessed); 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds } /* end __keyring_search_one() */ 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds /*****************************************************************************/ 5421da177e4SLinus Torvalds /* 5433e30148cSDavid Howells * search for an instantiation authorisation key matching a target key 5443e30148cSDavid Howells * - the RCU read lock must be held by the caller 5453e30148cSDavid Howells * - a target_id of zero specifies any valid token 5463e30148cSDavid Howells */ 5473e30148cSDavid Howells struct key *keyring_search_instkey(struct key *keyring, 5483e30148cSDavid Howells key_serial_t target_id) 5493e30148cSDavid Howells { 5503e30148cSDavid Howells struct request_key_auth *rka; 5513e30148cSDavid Howells struct keyring_list *klist; 5523e30148cSDavid Howells struct key *instkey; 5533e30148cSDavid Howells int loop; 5543e30148cSDavid Howells 5553e30148cSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 5563e30148cSDavid Howells if (klist) { 5573e30148cSDavid Howells for (loop = 0; loop < klist->nkeys; loop++) { 5583e30148cSDavid Howells instkey = klist->keys[loop]; 5593e30148cSDavid Howells 5603e30148cSDavid Howells if (instkey->type != &key_type_request_key_auth) 5613e30148cSDavid Howells continue; 5623e30148cSDavid Howells 5633e30148cSDavid Howells rka = instkey->payload.data; 5643e30148cSDavid Howells if (target_id && rka->target_key->serial != target_id) 5653e30148cSDavid Howells continue; 5663e30148cSDavid Howells 5673e30148cSDavid Howells /* the auth key is revoked during instantiation */ 5683e30148cSDavid Howells if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags)) 5693e30148cSDavid Howells goto found; 5703e30148cSDavid Howells 5713e30148cSDavid Howells instkey = ERR_PTR(-EKEYREVOKED); 5723e30148cSDavid Howells goto error; 5733e30148cSDavid Howells } 5743e30148cSDavid Howells } 5753e30148cSDavid Howells 5763e30148cSDavid Howells instkey = ERR_PTR(-EACCES); 5773e30148cSDavid Howells goto error; 5783e30148cSDavid Howells 5793e30148cSDavid Howells found: 5803e30148cSDavid Howells atomic_inc(&instkey->usage); 5813e30148cSDavid Howells error: 5823e30148cSDavid Howells return instkey; 5833e30148cSDavid Howells 5843e30148cSDavid Howells } /* end keyring_search_instkey() */ 5853e30148cSDavid Howells 5863e30148cSDavid Howells /*****************************************************************************/ 5873e30148cSDavid Howells /* 5881da177e4SLinus Torvalds * find a keyring with the specified name 5891da177e4SLinus Torvalds * - all named keyrings are searched 5901da177e4SLinus Torvalds * - only find keyrings with search permission for the process 5911da177e4SLinus Torvalds * - only find keyrings with a serial number greater than the one specified 5921da177e4SLinus Torvalds */ 5931da177e4SLinus Torvalds struct key *find_keyring_by_name(const char *name, key_serial_t bound) 5941da177e4SLinus Torvalds { 5951da177e4SLinus Torvalds struct key *keyring; 5961da177e4SLinus Torvalds int bucket; 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds keyring = ERR_PTR(-EINVAL); 5991da177e4SLinus Torvalds if (!name) 6001da177e4SLinus Torvalds goto error; 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 ) { 61376d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 6141da177e4SLinus Torvalds continue; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds if (strcmp(keyring->description, name) != 0) 6171da177e4SLinus Torvalds continue; 6181da177e4SLinus Torvalds 619*664cceb0SDavid Howells if (!key_permission(make_key_ref(keyring, 0), 620*664cceb0SDavid Howells KEY_SEARCH)) 6211da177e4SLinus Torvalds continue; 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds /* found a potential candidate, but we still need to 6241da177e4SLinus Torvalds * check the serial number */ 6251da177e4SLinus Torvalds if (keyring->serial <= bound) 6261da177e4SLinus Torvalds continue; 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds /* we've got a match */ 6291da177e4SLinus Torvalds atomic_inc(&keyring->usage); 6301da177e4SLinus Torvalds read_unlock(&keyring_name_lock); 6311da177e4SLinus Torvalds goto error; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds read_unlock(&keyring_name_lock); 6361da177e4SLinus Torvalds keyring = ERR_PTR(-ENOKEY); 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds error: 6391da177e4SLinus Torvalds return keyring; 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds } /* end find_keyring_by_name() */ 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds /*****************************************************************************/ 6441da177e4SLinus Torvalds /* 6451da177e4SLinus Torvalds * see if a cycle will will be created by inserting acyclic tree B in acyclic 6461da177e4SLinus Torvalds * tree A at the topmost level (ie: as a direct child of A) 6471da177e4SLinus Torvalds * - since we are adding B to A at the top level, checking for cycles should 6481da177e4SLinus Torvalds * just 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; 6591da177e4SLinus Torvalds int sp, 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 */ 6821da177e4SLinus Torvalds for (; kix < keylist->nkeys; kix++) { 6831da177e4SLinus Torvalds key = keylist->keys[kix]; 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds if (key == A) 6861da177e4SLinus Torvalds goto cycle_detected; 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds /* recursively check nested keyrings */ 6891da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 6901da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 6911da177e4SLinus Torvalds goto too_deep; 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds /* stack the current position */ 69476d8aeabSDavid Howells stack[sp].keylist = keylist; 6951da177e4SLinus Torvalds stack[sp].kix = kix; 6961da177e4SLinus Torvalds sp++; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* begin again with the new keyring */ 6991da177e4SLinus Torvalds subtree = key; 7001da177e4SLinus Torvalds goto descend; 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 7051da177e4SLinus Torvalds * matching key */ 7061da177e4SLinus Torvalds not_this_keyring: 7071da177e4SLinus Torvalds if (sp > 0) { 7081da177e4SLinus Torvalds /* resume the checking of a keyring higher up in the tree */ 7091da177e4SLinus Torvalds sp--; 71076d8aeabSDavid Howells keylist = stack[sp].keylist; 7111da177e4SLinus Torvalds kix = stack[sp].kix + 1; 7121da177e4SLinus Torvalds goto ascend; 7131da177e4SLinus Torvalds } 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds ret = 0; /* no cycles detected */ 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds error: 71876d8aeabSDavid Howells rcu_read_unlock(); 7191da177e4SLinus Torvalds return ret; 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds too_deep: 7221da177e4SLinus Torvalds ret = -ELOOP; 72376d8aeabSDavid Howells goto error; 72476d8aeabSDavid Howells 7251da177e4SLinus Torvalds cycle_detected: 7261da177e4SLinus Torvalds ret = -EDEADLK; 7271da177e4SLinus Torvalds goto error; 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds } /* end keyring_detect_cycle() */ 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds /*****************************************************************************/ 7321da177e4SLinus Torvalds /* 73376d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period 73476d8aeabSDavid Howells */ 73576d8aeabSDavid Howells static void keyring_link_rcu_disposal(struct rcu_head *rcu) 73676d8aeabSDavid Howells { 73776d8aeabSDavid Howells struct keyring_list *klist = 73876d8aeabSDavid Howells container_of(rcu, struct keyring_list, rcu); 73976d8aeabSDavid Howells 74076d8aeabSDavid Howells kfree(klist); 74176d8aeabSDavid Howells 74276d8aeabSDavid Howells } /* end keyring_link_rcu_disposal() */ 74376d8aeabSDavid Howells 74476d8aeabSDavid Howells /*****************************************************************************/ 74576d8aeabSDavid Howells /* 7461da177e4SLinus Torvalds * link a key into to a keyring 74776d8aeabSDavid Howells * - must be called with the keyring's semaphore write-locked 7481da177e4SLinus Torvalds */ 7491da177e4SLinus Torvalds int __key_link(struct key *keyring, struct key *key) 7501da177e4SLinus Torvalds { 7511da177e4SLinus Torvalds struct keyring_list *klist, *nklist; 7521da177e4SLinus Torvalds unsigned max; 7531da177e4SLinus Torvalds size_t size; 7541da177e4SLinus Torvalds int ret; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds ret = -EKEYREVOKED; 75776d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 7581da177e4SLinus Torvalds goto error; 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds ret = -ENOTDIR; 7611da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 7621da177e4SLinus Torvalds goto error; 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds /* serialise link/link calls to prevent parallel calls causing a 7651da177e4SLinus Torvalds * cycle when applied to two keyring in opposite orders */ 7661da177e4SLinus Torvalds down_write(&keyring_serialise_link_sem); 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds /* check that we aren't going to create a cycle adding one keyring to 7691da177e4SLinus Torvalds * another */ 7701da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 7711da177e4SLinus Torvalds ret = keyring_detect_cycle(keyring, key); 7721da177e4SLinus Torvalds if (ret < 0) 7731da177e4SLinus Torvalds goto error2; 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds /* check that we aren't going to overrun the user's quota */ 7771da177e4SLinus Torvalds ret = key_payload_reserve(keyring, 7781da177e4SLinus Torvalds keyring->datalen + KEYQUOTA_LINK_BYTES); 7791da177e4SLinus Torvalds if (ret < 0) 7801da177e4SLinus Torvalds goto error2; 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds if (klist && klist->nkeys < klist->maxkeys) { 7851da177e4SLinus Torvalds /* there's sufficient slack space to add directly */ 7861da177e4SLinus Torvalds atomic_inc(&key->usage); 7871da177e4SLinus Torvalds 78876d8aeabSDavid Howells klist->keys[klist->nkeys] = key; 78976d8aeabSDavid Howells smp_wmb(); 79076d8aeabSDavid Howells klist->nkeys++; 79176d8aeabSDavid Howells smp_wmb(); 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds ret = 0; 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds else { 7961da177e4SLinus Torvalds /* grow the key list */ 7971da177e4SLinus Torvalds max = 4; 7981da177e4SLinus Torvalds if (klist) 7991da177e4SLinus Torvalds max += klist->maxkeys; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds ret = -ENFILE; 80276d8aeabSDavid Howells if (max > 65535) 80376d8aeabSDavid Howells goto error3; 804a4014d8fSDavid Howells size = sizeof(*klist) + sizeof(struct key *) * max; 8051da177e4SLinus Torvalds if (size > PAGE_SIZE) 8061da177e4SLinus Torvalds goto error3; 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds ret = -ENOMEM; 8091da177e4SLinus Torvalds nklist = kmalloc(size, GFP_KERNEL); 8101da177e4SLinus Torvalds if (!nklist) 8111da177e4SLinus Torvalds goto error3; 8121da177e4SLinus Torvalds nklist->maxkeys = max; 8131da177e4SLinus Torvalds nklist->nkeys = 0; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds if (klist) { 8161da177e4SLinus Torvalds nklist->nkeys = klist->nkeys; 8171da177e4SLinus Torvalds memcpy(nklist->keys, 8181da177e4SLinus Torvalds klist->keys, 8191da177e4SLinus Torvalds sizeof(struct key *) * klist->nkeys); 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds /* add the key into the new space */ 8231da177e4SLinus Torvalds atomic_inc(&key->usage); 8241da177e4SLinus Torvalds nklist->keys[nklist->nkeys++] = key; 82576d8aeabSDavid Howells 82676d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds /* dispose of the old keyring list */ 82976d8aeabSDavid Howells if (klist) 83076d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_link_rcu_disposal); 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds ret = 0; 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds error2: 8361da177e4SLinus Torvalds up_write(&keyring_serialise_link_sem); 8371da177e4SLinus Torvalds error: 8381da177e4SLinus Torvalds return ret; 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds error3: 8411da177e4SLinus Torvalds /* undo the quota changes */ 8421da177e4SLinus Torvalds key_payload_reserve(keyring, 8431da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 8441da177e4SLinus Torvalds goto error2; 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds } /* end __key_link() */ 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds /*****************************************************************************/ 8491da177e4SLinus Torvalds /* 8501da177e4SLinus Torvalds * link a key to a keyring 8511da177e4SLinus Torvalds */ 8521da177e4SLinus Torvalds int key_link(struct key *keyring, struct key *key) 8531da177e4SLinus Torvalds { 8541da177e4SLinus Torvalds int ret; 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds key_check(keyring); 8571da177e4SLinus Torvalds key_check(key); 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds down_write(&keyring->sem); 8601da177e4SLinus Torvalds ret = __key_link(keyring, key); 8611da177e4SLinus Torvalds up_write(&keyring->sem); 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds return ret; 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds } /* end key_link() */ 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds EXPORT_SYMBOL(key_link); 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds /*****************************************************************************/ 8701da177e4SLinus Torvalds /* 87176d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period, freeing the unlinked 87276d8aeabSDavid Howells * key 87376d8aeabSDavid Howells */ 87476d8aeabSDavid Howells static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) 87576d8aeabSDavid Howells { 87676d8aeabSDavid Howells struct keyring_list *klist = 87776d8aeabSDavid Howells container_of(rcu, struct keyring_list, rcu); 87876d8aeabSDavid Howells 87976d8aeabSDavid Howells key_put(klist->keys[klist->delkey]); 88076d8aeabSDavid Howells kfree(klist); 88176d8aeabSDavid Howells 88276d8aeabSDavid Howells } /* end keyring_unlink_rcu_disposal() */ 88376d8aeabSDavid Howells 88476d8aeabSDavid Howells /*****************************************************************************/ 88576d8aeabSDavid Howells /* 8861da177e4SLinus Torvalds * unlink the first link to a key from a keyring 8871da177e4SLinus Torvalds */ 8881da177e4SLinus Torvalds int key_unlink(struct key *keyring, struct key *key) 8891da177e4SLinus Torvalds { 89076d8aeabSDavid Howells struct keyring_list *klist, *nklist; 8911da177e4SLinus Torvalds int loop, ret; 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds key_check(keyring); 8941da177e4SLinus Torvalds key_check(key); 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds ret = -ENOTDIR; 8971da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 8981da177e4SLinus Torvalds goto error; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds down_write(&keyring->sem); 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 9031da177e4SLinus Torvalds if (klist) { 9041da177e4SLinus Torvalds /* search the keyring for the key */ 9051da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) 9061da177e4SLinus Torvalds if (klist->keys[loop] == key) 9071da177e4SLinus Torvalds goto key_is_present; 9081da177e4SLinus Torvalds } 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds up_write(&keyring->sem); 9111da177e4SLinus Torvalds ret = -ENOENT; 9121da177e4SLinus Torvalds goto error; 9131da177e4SLinus Torvalds 9141da177e4SLinus Torvalds key_is_present: 91576d8aeabSDavid Howells /* we need to copy the key list for RCU purposes */ 916a4014d8fSDavid Howells nklist = kmalloc(sizeof(*klist) + 917a4014d8fSDavid Howells sizeof(struct key *) * klist->maxkeys, 91876d8aeabSDavid Howells GFP_KERNEL); 91976d8aeabSDavid Howells if (!nklist) 92076d8aeabSDavid Howells goto nomem; 92176d8aeabSDavid Howells nklist->maxkeys = klist->maxkeys; 92276d8aeabSDavid Howells nklist->nkeys = klist->nkeys - 1; 92376d8aeabSDavid Howells 92476d8aeabSDavid Howells if (loop > 0) 92576d8aeabSDavid Howells memcpy(&nklist->keys[0], 92676d8aeabSDavid Howells &klist->keys[0], 927a4014d8fSDavid Howells loop * sizeof(struct key *)); 92876d8aeabSDavid Howells 92976d8aeabSDavid Howells if (loop < nklist->nkeys) 93076d8aeabSDavid Howells memcpy(&nklist->keys[loop], 93176d8aeabSDavid Howells &klist->keys[loop + 1], 932a4014d8fSDavid Howells (nklist->nkeys - loop) * sizeof(struct key *)); 93376d8aeabSDavid Howells 9341da177e4SLinus Torvalds /* adjust the user's quota */ 9351da177e4SLinus Torvalds key_payload_reserve(keyring, 9361da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 9371da177e4SLinus Torvalds 93876d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds up_write(&keyring->sem); 94176d8aeabSDavid Howells 94276d8aeabSDavid Howells /* schedule for later cleanup */ 94376d8aeabSDavid Howells klist->delkey = loop; 94476d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 94576d8aeabSDavid Howells 9461da177e4SLinus Torvalds ret = 0; 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds error: 9491da177e4SLinus Torvalds return ret; 95076d8aeabSDavid Howells nomem: 95176d8aeabSDavid Howells ret = -ENOMEM; 95276d8aeabSDavid Howells up_write(&keyring->sem); 95376d8aeabSDavid Howells goto error; 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds } /* end key_unlink() */ 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds EXPORT_SYMBOL(key_unlink); 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds /*****************************************************************************/ 9601da177e4SLinus Torvalds /* 96176d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period, releasing the keys it 96276d8aeabSDavid Howells * links to 96376d8aeabSDavid Howells */ 96476d8aeabSDavid Howells static void keyring_clear_rcu_disposal(struct rcu_head *rcu) 96576d8aeabSDavid Howells { 96676d8aeabSDavid Howells struct keyring_list *klist; 96776d8aeabSDavid Howells int loop; 96876d8aeabSDavid Howells 96976d8aeabSDavid Howells klist = container_of(rcu, struct keyring_list, rcu); 97076d8aeabSDavid Howells 97176d8aeabSDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 97276d8aeabSDavid Howells key_put(klist->keys[loop]); 97376d8aeabSDavid Howells 97476d8aeabSDavid Howells kfree(klist); 97576d8aeabSDavid Howells 97676d8aeabSDavid Howells } /* end keyring_clear_rcu_disposal() */ 97776d8aeabSDavid Howells 97876d8aeabSDavid Howells /*****************************************************************************/ 97976d8aeabSDavid Howells /* 9801da177e4SLinus Torvalds * clear the specified process keyring 9811da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CLEAR) 9821da177e4SLinus Torvalds */ 9831da177e4SLinus Torvalds int keyring_clear(struct key *keyring) 9841da177e4SLinus Torvalds { 9851da177e4SLinus Torvalds struct keyring_list *klist; 98676d8aeabSDavid Howells int ret; 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds ret = -ENOTDIR; 9891da177e4SLinus Torvalds if (keyring->type == &key_type_keyring) { 9901da177e4SLinus Torvalds /* detach the pointer block with the locks held */ 9911da177e4SLinus Torvalds down_write(&keyring->sem); 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 9941da177e4SLinus Torvalds if (klist) { 9951da177e4SLinus Torvalds /* adjust the quota */ 9961da177e4SLinus Torvalds key_payload_reserve(keyring, 9971da177e4SLinus Torvalds sizeof(struct keyring_list)); 9981da177e4SLinus Torvalds 99976d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, 100076d8aeabSDavid Howells NULL); 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds up_write(&keyring->sem); 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds /* free the keys after the locks have been dropped */ 100676d8aeabSDavid Howells if (klist) 100776d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds ret = 0; 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds return ret; 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds } /* end keyring_clear() */ 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_clear); 1017