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> 1629db9190SDavid Howells #include <linux/security.h> 171da177e4SLinus Torvalds #include <linux/seq_file.h> 181da177e4SLinus Torvalds #include <linux/err.h> 191da177e4SLinus Torvalds #include <asm/uaccess.h> 201da177e4SLinus Torvalds #include "internal.h" 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds /* 231da177e4SLinus Torvalds * when plumbing the depths of the key tree, this sets a hard limit set on how 241da177e4SLinus Torvalds * deep we're willing to go 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds #define KEYRING_SEARCH_MAX_DEPTH 6 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* 291da177e4SLinus Torvalds * we keep all named keyrings in a hash to speed looking them up 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds #define KEYRING_NAME_HASH_SIZE (1 << 5) 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; 341da177e4SLinus Torvalds static DEFINE_RWLOCK(keyring_name_lock); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static inline unsigned keyring_hash(const char *desc) 371da177e4SLinus Torvalds { 381da177e4SLinus Torvalds unsigned bucket = 0; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds for (; *desc; desc++) 411da177e4SLinus Torvalds bucket += (unsigned char) *desc; 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds return bucket & (KEYRING_NAME_HASH_SIZE - 1); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* 471da177e4SLinus Torvalds * the keyring type definition 481da177e4SLinus Torvalds */ 491da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 501da177e4SLinus Torvalds const void *data, size_t datalen); 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 .match = keyring_match, 621da177e4SLinus Torvalds .destroy = keyring_destroy, 631da177e4SLinus Torvalds .describe = keyring_describe, 641da177e4SLinus Torvalds .read = keyring_read, 651da177e4SLinus Torvalds }; 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds /* 681da177e4SLinus Torvalds * semaphore to serialise link/link calls to prevent two link calls in parallel 691da177e4SLinus Torvalds * introducing a cycle 701da177e4SLinus Torvalds */ 711ae8f407SAdrian Bunk static DECLARE_RWSEM(keyring_serialise_link_sem); 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /*****************************************************************************/ 741da177e4SLinus Torvalds /* 751da177e4SLinus Torvalds * publish the name of a keyring so that it can be found by name (if it has 761da177e4SLinus Torvalds * one) 771da177e4SLinus Torvalds */ 781da177e4SLinus Torvalds void keyring_publish_name(struct key *keyring) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds int bucket; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds if (keyring->description) { 831da177e4SLinus Torvalds bucket = keyring_hash(keyring->description); 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds write_lock(&keyring_name_lock); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds if (!keyring_name_hash[bucket].next) 881da177e4SLinus Torvalds INIT_LIST_HEAD(&keyring_name_hash[bucket]); 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds list_add_tail(&keyring->type_data.link, 911da177e4SLinus Torvalds &keyring_name_hash[bucket]); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds } /* end keyring_publish_name() */ 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds /*****************************************************************************/ 991da177e4SLinus Torvalds /* 1001da177e4SLinus Torvalds * initialise a keyring 1011da177e4SLinus Torvalds * - we object if we were given any data 1021da177e4SLinus Torvalds */ 1031da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 1041da177e4SLinus Torvalds const void *data, size_t datalen) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds int ret; 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds ret = -EINVAL; 1091da177e4SLinus Torvalds if (datalen == 0) { 1101da177e4SLinus Torvalds /* make the keyring available by name if it has one */ 1111da177e4SLinus Torvalds keyring_publish_name(keyring); 1121da177e4SLinus Torvalds ret = 0; 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds return ret; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds } /* end keyring_instantiate() */ 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /*****************************************************************************/ 1201da177e4SLinus Torvalds /* 1211da177e4SLinus Torvalds * match keyrings on their name 1221da177e4SLinus Torvalds */ 1231da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *description) 1241da177e4SLinus Torvalds { 1251da177e4SLinus Torvalds return keyring->description && 1261da177e4SLinus Torvalds strcmp(keyring->description, description) == 0; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds } /* end keyring_match() */ 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds /*****************************************************************************/ 1311da177e4SLinus Torvalds /* 1321da177e4SLinus Torvalds * dispose of the data dangling from the corpse of a keyring 1331da177e4SLinus Torvalds */ 1341da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring) 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds struct keyring_list *klist; 1371da177e4SLinus Torvalds int loop; 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds if (keyring->description) { 1401da177e4SLinus Torvalds write_lock(&keyring_name_lock); 14194efe72fSDavid Howells 14294efe72fSDavid Howells if (keyring->type_data.link.next != NULL && 14394efe72fSDavid Howells !list_empty(&keyring->type_data.link)) 1441da177e4SLinus Torvalds list_del(&keyring->type_data.link); 14594efe72fSDavid Howells 1461da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds 14976d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 1501da177e4SLinus Torvalds if (klist) { 1511da177e4SLinus Torvalds for (loop = klist->nkeys - 1; loop >= 0; loop--) 1521da177e4SLinus Torvalds key_put(klist->keys[loop]); 1531da177e4SLinus Torvalds kfree(klist); 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds } /* end keyring_destroy() */ 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds /*****************************************************************************/ 1591da177e4SLinus Torvalds /* 1601da177e4SLinus Torvalds * describe the keyring 1611da177e4SLinus Torvalds */ 1621da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds struct keyring_list *klist; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds if (keyring->description) { 1671da177e4SLinus Torvalds seq_puts(m, keyring->description); 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds else { 1701da177e4SLinus Torvalds seq_puts(m, "[anon]"); 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds 17376d8aeabSDavid Howells rcu_read_lock(); 17476d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 1751da177e4SLinus Torvalds if (klist) 1761da177e4SLinus Torvalds seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); 1771da177e4SLinus Torvalds else 1781da177e4SLinus Torvalds seq_puts(m, ": empty"); 17976d8aeabSDavid Howells rcu_read_unlock(); 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds } /* end keyring_describe() */ 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds /*****************************************************************************/ 1841da177e4SLinus Torvalds /* 1851da177e4SLinus Torvalds * read a list of key IDs from the keyring's contents 18676d8aeabSDavid Howells * - the keyring's semaphore is read-locked 1871da177e4SLinus Torvalds */ 1881da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 1891da177e4SLinus Torvalds char __user *buffer, size_t buflen) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds struct keyring_list *klist; 1921da177e4SLinus Torvalds struct key *key; 1931da177e4SLinus Torvalds size_t qty, tmp; 1941da177e4SLinus Torvalds int loop, ret; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds ret = 0; 19776d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds if (klist) { 2001da177e4SLinus Torvalds /* calculate how much data we could return */ 2011da177e4SLinus Torvalds qty = klist->nkeys * sizeof(key_serial_t); 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds if (buffer && buflen > 0) { 2041da177e4SLinus Torvalds if (buflen > qty) 2051da177e4SLinus Torvalds buflen = qty; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* copy the IDs of the subscribed keys into the 2081da177e4SLinus Torvalds * buffer */ 2091da177e4SLinus Torvalds ret = -EFAULT; 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 2121da177e4SLinus Torvalds key = klist->keys[loop]; 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds tmp = sizeof(key_serial_t); 2151da177e4SLinus Torvalds if (tmp > buflen) 2161da177e4SLinus Torvalds tmp = buflen; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds if (copy_to_user(buffer, 2191da177e4SLinus Torvalds &key->serial, 2201da177e4SLinus Torvalds tmp) != 0) 2211da177e4SLinus Torvalds goto error; 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds buflen -= tmp; 2241da177e4SLinus Torvalds if (buflen == 0) 2251da177e4SLinus Torvalds break; 2261da177e4SLinus Torvalds buffer += tmp; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds ret = qty; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds error: 2341da177e4SLinus Torvalds return ret; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds } /* end keyring_read() */ 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds /*****************************************************************************/ 2391da177e4SLinus Torvalds /* 2401da177e4SLinus Torvalds * allocate a keyring and link into the destination keyring 2411da177e4SLinus Torvalds */ 2421da177e4SLinus Torvalds struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, 243*d720024eSMichael LeMay struct task_struct *ctx, int not_in_quota, 244*d720024eSMichael LeMay struct key *dest) 2451da177e4SLinus Torvalds { 2461da177e4SLinus Torvalds struct key *keyring; 2471da177e4SLinus Torvalds int ret; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds keyring = key_alloc(&key_type_keyring, description, 250*d720024eSMichael LeMay uid, gid, ctx, 25129db9190SDavid Howells (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, 25229db9190SDavid Howells not_in_quota); 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds if (!IS_ERR(keyring)) { 2553e30148cSDavid Howells ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); 2561da177e4SLinus Torvalds if (ret < 0) { 2571da177e4SLinus Torvalds key_put(keyring); 2581da177e4SLinus Torvalds keyring = ERR_PTR(ret); 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds return keyring; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds } /* end keyring_alloc() */ 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /*****************************************************************************/ 2671da177e4SLinus Torvalds /* 2681da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 2691da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 2701da177e4SLinus Torvalds * - we only find keys on which we have search permission 2711da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 2721da177e4SLinus Torvalds * feature of interest) matches 2733e30148cSDavid Howells * - we rely on RCU to prevent the keyring lists from disappearing on us 2741da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 2751da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 276664cceb0SDavid Howells * - we propagate the possession attribute from the keyring ref to the key ref 2771da177e4SLinus Torvalds */ 278664cceb0SDavid Howells key_ref_t keyring_search_aux(key_ref_t keyring_ref, 2793e30148cSDavid Howells struct task_struct *context, 2801da177e4SLinus Torvalds struct key_type *type, 2811da177e4SLinus Torvalds const void *description, 2821da177e4SLinus Torvalds key_match_func_t match) 2831da177e4SLinus Torvalds { 2841da177e4SLinus Torvalds struct { 28576d8aeabSDavid Howells struct keyring_list *keylist; 2861da177e4SLinus Torvalds int kix; 2871da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds struct keyring_list *keylist; 2901da177e4SLinus Torvalds struct timespec now; 291664cceb0SDavid Howells unsigned long possessed; 292664cceb0SDavid Howells struct key *keyring, *key; 293664cceb0SDavid Howells key_ref_t key_ref; 2941da177e4SLinus Torvalds long err; 29576d8aeabSDavid Howells int sp, kix; 2961da177e4SLinus Torvalds 297664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 298664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 2991da177e4SLinus Torvalds key_check(keyring); 3001da177e4SLinus Torvalds 3011da177e4SLinus Torvalds /* top keyring must have search permission to begin the search */ 30229db9190SDavid Howells err = key_task_permission(keyring_ref, context, KEY_SEARCH); 30329db9190SDavid Howells if (err < 0) { 30429db9190SDavid Howells key_ref = ERR_PTR(err); 3051da177e4SLinus Torvalds goto error; 30629db9190SDavid Howells } 3071da177e4SLinus Torvalds 308664cceb0SDavid Howells key_ref = ERR_PTR(-ENOTDIR); 3091da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 3101da177e4SLinus Torvalds goto error; 3111da177e4SLinus Torvalds 312664cceb0SDavid Howells rcu_read_lock(); 313664cceb0SDavid Howells 3141da177e4SLinus Torvalds now = current_kernel_time(); 3151da177e4SLinus Torvalds err = -EAGAIN; 3161da177e4SLinus Torvalds sp = 0; 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds /* start processing a new keyring */ 3191da177e4SLinus Torvalds descend: 32076d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 3211da177e4SLinus Torvalds goto not_this_keyring; 3221da177e4SLinus Torvalds 32376d8aeabSDavid Howells keylist = rcu_dereference(keyring->payload.subscriptions); 3241da177e4SLinus Torvalds if (!keylist) 3251da177e4SLinus Torvalds goto not_this_keyring; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds /* iterate through the keys in this keyring first */ 3281da177e4SLinus Torvalds for (kix = 0; kix < keylist->nkeys; kix++) { 3291da177e4SLinus Torvalds key = keylist->keys[kix]; 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* ignore keys not of this type */ 3321da177e4SLinus Torvalds if (key->type != type) 3331da177e4SLinus Torvalds continue; 3341da177e4SLinus Torvalds 3351da177e4SLinus Torvalds /* skip revoked keys and expired keys */ 33676d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &key->flags)) 3371da177e4SLinus Torvalds continue; 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds if (key->expiry && now.tv_sec >= key->expiry) 3401da177e4SLinus Torvalds continue; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds /* keys that don't match */ 3431da177e4SLinus Torvalds if (!match(key, description)) 3441da177e4SLinus Torvalds continue; 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds /* key must have search permissions */ 34729db9190SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 34829db9190SDavid Howells context, KEY_SEARCH) < 0) 3491da177e4SLinus Torvalds continue; 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds /* we set a different error code if we find a negative key */ 35276d8aeabSDavid Howells if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { 3531da177e4SLinus Torvalds err = -ENOKEY; 3541da177e4SLinus Torvalds continue; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds goto found; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* search through the keyrings nested in this one */ 3611da177e4SLinus Torvalds kix = 0; 3621da177e4SLinus Torvalds ascend: 36376d8aeabSDavid Howells for (; kix < keylist->nkeys; kix++) { 3641da177e4SLinus Torvalds key = keylist->keys[kix]; 3651da177e4SLinus Torvalds if (key->type != &key_type_keyring) 36676d8aeabSDavid Howells continue; 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds /* recursively search nested keyrings 3691da177e4SLinus Torvalds * - only search keyrings for which we have search permission 3701da177e4SLinus Torvalds */ 3711da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 37276d8aeabSDavid Howells continue; 3731da177e4SLinus Torvalds 3740f6ed7c2SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 37529db9190SDavid Howells context, KEY_SEARCH) < 0) 37676d8aeabSDavid Howells continue; 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds /* stack the current position */ 37976d8aeabSDavid Howells stack[sp].keylist = keylist; 3801da177e4SLinus Torvalds stack[sp].kix = kix; 3811da177e4SLinus Torvalds sp++; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds /* begin again with the new keyring */ 3841da177e4SLinus Torvalds keyring = key; 3851da177e4SLinus Torvalds goto descend; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 3891da177e4SLinus Torvalds * matching key */ 3901da177e4SLinus Torvalds not_this_keyring: 3911da177e4SLinus Torvalds if (sp > 0) { 3921da177e4SLinus Torvalds /* resume the processing of a keyring higher up in the tree */ 3931da177e4SLinus Torvalds sp--; 39476d8aeabSDavid Howells keylist = stack[sp].keylist; 3951da177e4SLinus Torvalds kix = stack[sp].kix + 1; 3961da177e4SLinus Torvalds goto ascend; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 399664cceb0SDavid Howells key_ref = ERR_PTR(err); 400664cceb0SDavid Howells goto error_2; 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds /* we found a viable match */ 4031da177e4SLinus Torvalds found: 4041da177e4SLinus Torvalds atomic_inc(&key->usage); 4051da177e4SLinus Torvalds key_check(key); 406664cceb0SDavid Howells key_ref = make_key_ref(key, possessed); 407664cceb0SDavid Howells error_2: 40876d8aeabSDavid Howells rcu_read_unlock(); 409664cceb0SDavid Howells error: 410664cceb0SDavid Howells return key_ref; 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds } /* end keyring_search_aux() */ 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /*****************************************************************************/ 4151da177e4SLinus Torvalds /* 4161da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 4171da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 4181da177e4SLinus Torvalds * - we only find keys on which we have search permission 4191da177e4SLinus Torvalds * - we readlock the keyrings as we search down the tree 4201da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 4211da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 4221da177e4SLinus Torvalds */ 423664cceb0SDavid Howells key_ref_t keyring_search(key_ref_t keyring, 4241da177e4SLinus Torvalds struct key_type *type, 4251da177e4SLinus Torvalds const char *description) 4261da177e4SLinus Torvalds { 4273e30148cSDavid Howells if (!type->match) 4283e30148cSDavid Howells return ERR_PTR(-ENOKEY); 4293e30148cSDavid Howells 4303e30148cSDavid Howells return keyring_search_aux(keyring, current, 4313e30148cSDavid Howells type, description, type->match); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds } /* end keyring_search() */ 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_search); 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds /*****************************************************************************/ 4381da177e4SLinus Torvalds /* 4391da177e4SLinus Torvalds * search the given keyring only (no recursion) 4401da177e4SLinus Torvalds * - keyring must be locked by caller 441c3a9d654SDavid Howells * - caller must guarantee that the keyring is a keyring 4421da177e4SLinus Torvalds */ 443664cceb0SDavid Howells key_ref_t __keyring_search_one(key_ref_t keyring_ref, 4441da177e4SLinus Torvalds const struct key_type *ktype, 4451da177e4SLinus Torvalds const char *description, 4461da177e4SLinus Torvalds key_perm_t perm) 4471da177e4SLinus Torvalds { 4481da177e4SLinus Torvalds struct keyring_list *klist; 449664cceb0SDavid Howells unsigned long possessed; 450664cceb0SDavid Howells struct key *keyring, *key; 4511da177e4SLinus Torvalds int loop; 4521da177e4SLinus Torvalds 453664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 454664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 455664cceb0SDavid Howells 45676d8aeabSDavid Howells rcu_read_lock(); 45776d8aeabSDavid Howells 45876d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 4591da177e4SLinus Torvalds if (klist) { 4601da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 4611da177e4SLinus Torvalds key = klist->keys[loop]; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds if (key->type == ktype && 4643e30148cSDavid Howells (!key->type->match || 4653e30148cSDavid Howells key->type->match(key, description)) && 466664cceb0SDavid Howells key_permission(make_key_ref(key, possessed), 467db1d1d57SDavid Howells perm) == 0 && 46876d8aeabSDavid Howells !test_bit(KEY_FLAG_REVOKED, &key->flags) 4691da177e4SLinus Torvalds ) 4701da177e4SLinus Torvalds goto found; 4711da177e4SLinus Torvalds } 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 474664cceb0SDavid Howells rcu_read_unlock(); 475664cceb0SDavid Howells return ERR_PTR(-ENOKEY); 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds found: 4781da177e4SLinus Torvalds atomic_inc(&key->usage); 47976d8aeabSDavid Howells rcu_read_unlock(); 480664cceb0SDavid Howells return make_key_ref(key, possessed); 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds } /* end __keyring_search_one() */ 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds /*****************************************************************************/ 4851da177e4SLinus Torvalds /* 4861da177e4SLinus Torvalds * find a keyring with the specified name 4871da177e4SLinus Torvalds * - all named keyrings are searched 4881da177e4SLinus Torvalds * - only find keyrings with search permission for the process 4891da177e4SLinus Torvalds * - only find keyrings with a serial number greater than the one specified 4901da177e4SLinus Torvalds */ 4911da177e4SLinus Torvalds struct key *find_keyring_by_name(const char *name, key_serial_t bound) 4921da177e4SLinus Torvalds { 4931da177e4SLinus Torvalds struct key *keyring; 4941da177e4SLinus Torvalds int bucket; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds keyring = ERR_PTR(-EINVAL); 4971da177e4SLinus Torvalds if (!name) 4981da177e4SLinus Torvalds goto error; 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds bucket = keyring_hash(name); 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds read_lock(&keyring_name_lock); 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds if (keyring_name_hash[bucket].next) { 5051da177e4SLinus Torvalds /* search this hash bucket for a keyring with a matching name 5061da177e4SLinus Torvalds * that's readable and that hasn't been revoked */ 5071da177e4SLinus Torvalds list_for_each_entry(keyring, 5081da177e4SLinus Torvalds &keyring_name_hash[bucket], 5091da177e4SLinus Torvalds type_data.link 5101da177e4SLinus Torvalds ) { 51176d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 5121da177e4SLinus Torvalds continue; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds if (strcmp(keyring->description, name) != 0) 5151da177e4SLinus Torvalds continue; 5161da177e4SLinus Torvalds 5170f6ed7c2SDavid Howells if (key_permission(make_key_ref(keyring, 0), 51829db9190SDavid Howells KEY_SEARCH) < 0) 5191da177e4SLinus Torvalds continue; 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds /* found a potential candidate, but we still need to 5221da177e4SLinus Torvalds * check the serial number */ 5231da177e4SLinus Torvalds if (keyring->serial <= bound) 5241da177e4SLinus Torvalds continue; 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds /* we've got a match */ 5271da177e4SLinus Torvalds atomic_inc(&keyring->usage); 5281da177e4SLinus Torvalds read_unlock(&keyring_name_lock); 5291da177e4SLinus Torvalds goto error; 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds read_unlock(&keyring_name_lock); 5341da177e4SLinus Torvalds keyring = ERR_PTR(-ENOKEY); 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds error: 5371da177e4SLinus Torvalds return keyring; 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds } /* end find_keyring_by_name() */ 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds /*****************************************************************************/ 5421da177e4SLinus Torvalds /* 5431da177e4SLinus Torvalds * see if a cycle will will be created by inserting acyclic tree B in acyclic 5441da177e4SLinus Torvalds * tree A at the topmost level (ie: as a direct child of A) 5451da177e4SLinus Torvalds * - since we are adding B to A at the top level, checking for cycles should 5461da177e4SLinus Torvalds * just be a matter of seeing if node A is somewhere in tree B 5471da177e4SLinus Torvalds */ 5481da177e4SLinus Torvalds static int keyring_detect_cycle(struct key *A, struct key *B) 5491da177e4SLinus Torvalds { 5501da177e4SLinus Torvalds struct { 55176d8aeabSDavid Howells struct keyring_list *keylist; 5521da177e4SLinus Torvalds int kix; 5531da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds struct keyring_list *keylist; 5561da177e4SLinus Torvalds struct key *subtree, *key; 5571da177e4SLinus Torvalds int sp, kix, ret; 5581da177e4SLinus Torvalds 55976d8aeabSDavid Howells rcu_read_lock(); 56076d8aeabSDavid Howells 5611da177e4SLinus Torvalds ret = -EDEADLK; 5621da177e4SLinus Torvalds if (A == B) 56376d8aeabSDavid Howells goto cycle_detected; 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds subtree = B; 5661da177e4SLinus Torvalds sp = 0; 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds /* start processing a new keyring */ 5691da177e4SLinus Torvalds descend: 57076d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) 5711da177e4SLinus Torvalds goto not_this_keyring; 5721da177e4SLinus Torvalds 57376d8aeabSDavid Howells keylist = rcu_dereference(subtree->payload.subscriptions); 5741da177e4SLinus Torvalds if (!keylist) 5751da177e4SLinus Torvalds goto not_this_keyring; 5761da177e4SLinus Torvalds kix = 0; 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds ascend: 5791da177e4SLinus Torvalds /* iterate through the remaining keys in this keyring */ 5801da177e4SLinus Torvalds for (; kix < keylist->nkeys; kix++) { 5811da177e4SLinus Torvalds key = keylist->keys[kix]; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds if (key == A) 5841da177e4SLinus Torvalds goto cycle_detected; 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds /* recursively check nested keyrings */ 5871da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 5881da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 5891da177e4SLinus Torvalds goto too_deep; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds /* stack the current position */ 59276d8aeabSDavid Howells stack[sp].keylist = keylist; 5931da177e4SLinus Torvalds stack[sp].kix = kix; 5941da177e4SLinus Torvalds sp++; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds /* begin again with the new keyring */ 5971da177e4SLinus Torvalds subtree = key; 5981da177e4SLinus Torvalds goto descend; 5991da177e4SLinus Torvalds } 6001da177e4SLinus Torvalds } 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 6031da177e4SLinus Torvalds * matching key */ 6041da177e4SLinus Torvalds not_this_keyring: 6051da177e4SLinus Torvalds if (sp > 0) { 6061da177e4SLinus Torvalds /* resume the checking of a keyring higher up in the tree */ 6071da177e4SLinus Torvalds sp--; 60876d8aeabSDavid Howells keylist = stack[sp].keylist; 6091da177e4SLinus Torvalds kix = stack[sp].kix + 1; 6101da177e4SLinus Torvalds goto ascend; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds ret = 0; /* no cycles detected */ 6141da177e4SLinus Torvalds 6151da177e4SLinus Torvalds error: 61676d8aeabSDavid Howells rcu_read_unlock(); 6171da177e4SLinus Torvalds return ret; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds too_deep: 6201da177e4SLinus Torvalds ret = -ELOOP; 62176d8aeabSDavid Howells goto error; 62276d8aeabSDavid Howells 6231da177e4SLinus Torvalds cycle_detected: 6241da177e4SLinus Torvalds ret = -EDEADLK; 6251da177e4SLinus Torvalds goto error; 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds } /* end keyring_detect_cycle() */ 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds /*****************************************************************************/ 6301da177e4SLinus Torvalds /* 63176d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period 63276d8aeabSDavid Howells */ 63376d8aeabSDavid Howells static void keyring_link_rcu_disposal(struct rcu_head *rcu) 63476d8aeabSDavid Howells { 63576d8aeabSDavid Howells struct keyring_list *klist = 63676d8aeabSDavid Howells container_of(rcu, struct keyring_list, rcu); 63776d8aeabSDavid Howells 63876d8aeabSDavid Howells kfree(klist); 63976d8aeabSDavid Howells 64076d8aeabSDavid Howells } /* end keyring_link_rcu_disposal() */ 64176d8aeabSDavid Howells 64276d8aeabSDavid Howells /*****************************************************************************/ 64376d8aeabSDavid Howells /* 644cab8eb59SDavid Howells * dispose of a keyring list after the RCU grace period, freeing the unlinked 645cab8eb59SDavid Howells * key 646cab8eb59SDavid Howells */ 647cab8eb59SDavid Howells static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) 648cab8eb59SDavid Howells { 649cab8eb59SDavid Howells struct keyring_list *klist = 650cab8eb59SDavid Howells container_of(rcu, struct keyring_list, rcu); 651cab8eb59SDavid Howells 652cab8eb59SDavid Howells key_put(klist->keys[klist->delkey]); 653cab8eb59SDavid Howells kfree(klist); 654cab8eb59SDavid Howells 655cab8eb59SDavid Howells } /* end keyring_unlink_rcu_disposal() */ 656cab8eb59SDavid Howells 657cab8eb59SDavid Howells /*****************************************************************************/ 658cab8eb59SDavid Howells /* 6591da177e4SLinus Torvalds * link a key into to a keyring 66076d8aeabSDavid Howells * - must be called with the keyring's semaphore write-locked 661cab8eb59SDavid Howells * - discard already extant link to matching key if there is one 6621da177e4SLinus Torvalds */ 6631da177e4SLinus Torvalds int __key_link(struct key *keyring, struct key *key) 6641da177e4SLinus Torvalds { 6651da177e4SLinus Torvalds struct keyring_list *klist, *nklist; 6661da177e4SLinus Torvalds unsigned max; 6671da177e4SLinus Torvalds size_t size; 668cab8eb59SDavid Howells int loop, ret; 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds ret = -EKEYREVOKED; 67176d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 6721da177e4SLinus Torvalds goto error; 6731da177e4SLinus Torvalds 6741da177e4SLinus Torvalds ret = -ENOTDIR; 6751da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 6761da177e4SLinus Torvalds goto error; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds /* serialise link/link calls to prevent parallel calls causing a 6791da177e4SLinus Torvalds * cycle when applied to two keyring in opposite orders */ 6801da177e4SLinus Torvalds down_write(&keyring_serialise_link_sem); 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds /* check that we aren't going to create a cycle adding one keyring to 6831da177e4SLinus Torvalds * another */ 6841da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 6851da177e4SLinus Torvalds ret = keyring_detect_cycle(keyring, key); 6861da177e4SLinus Torvalds if (ret < 0) 6871da177e4SLinus Torvalds goto error2; 6881da177e4SLinus Torvalds } 6891da177e4SLinus Torvalds 690cab8eb59SDavid Howells /* see if there's a matching key we can displace */ 691cab8eb59SDavid Howells klist = keyring->payload.subscriptions; 692cab8eb59SDavid Howells 693cab8eb59SDavid Howells if (klist && klist->nkeys > 0) { 694cab8eb59SDavid Howells struct key_type *type = key->type; 695cab8eb59SDavid Howells 696cab8eb59SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 697cab8eb59SDavid Howells if (klist->keys[loop]->type == type && 698cab8eb59SDavid Howells strcmp(klist->keys[loop]->description, 699cab8eb59SDavid Howells key->description) == 0 700cab8eb59SDavid Howells ) { 701cab8eb59SDavid Howells /* found a match - replace with new key */ 702cab8eb59SDavid Howells size = sizeof(struct key *) * klist->maxkeys; 703cab8eb59SDavid Howells size += sizeof(*klist); 704cab8eb59SDavid Howells BUG_ON(size > PAGE_SIZE); 705cab8eb59SDavid Howells 706cab8eb59SDavid Howells ret = -ENOMEM; 707cab8eb59SDavid Howells nklist = kmalloc(size, GFP_KERNEL); 708cab8eb59SDavid Howells if (!nklist) 709cab8eb59SDavid Howells goto error2; 710cab8eb59SDavid Howells 711cab8eb59SDavid Howells memcpy(nklist, klist, size); 712cab8eb59SDavid Howells 713cab8eb59SDavid Howells /* replace matched key */ 714cab8eb59SDavid Howells atomic_inc(&key->usage); 715cab8eb59SDavid Howells nklist->keys[loop] = key; 716cab8eb59SDavid Howells 717cab8eb59SDavid Howells rcu_assign_pointer( 718cab8eb59SDavid Howells keyring->payload.subscriptions, 719cab8eb59SDavid Howells nklist); 720cab8eb59SDavid Howells 721cab8eb59SDavid Howells /* dispose of the old keyring list and the 722cab8eb59SDavid Howells * displaced key */ 723cab8eb59SDavid Howells klist->delkey = loop; 724cab8eb59SDavid Howells call_rcu(&klist->rcu, 725cab8eb59SDavid Howells keyring_unlink_rcu_disposal); 726cab8eb59SDavid Howells 727cab8eb59SDavid Howells goto done; 728cab8eb59SDavid Howells } 729cab8eb59SDavid Howells } 730cab8eb59SDavid Howells } 731cab8eb59SDavid Howells 7321da177e4SLinus Torvalds /* check that we aren't going to overrun the user's quota */ 7331da177e4SLinus Torvalds ret = key_payload_reserve(keyring, 7341da177e4SLinus Torvalds keyring->datalen + KEYQUOTA_LINK_BYTES); 7351da177e4SLinus Torvalds if (ret < 0) 7361da177e4SLinus Torvalds goto error2; 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 7391da177e4SLinus Torvalds 7401da177e4SLinus Torvalds if (klist && klist->nkeys < klist->maxkeys) { 7411da177e4SLinus Torvalds /* there's sufficient slack space to add directly */ 7421da177e4SLinus Torvalds atomic_inc(&key->usage); 7431da177e4SLinus Torvalds 74476d8aeabSDavid Howells klist->keys[klist->nkeys] = key; 74576d8aeabSDavid Howells smp_wmb(); 74676d8aeabSDavid Howells klist->nkeys++; 74776d8aeabSDavid Howells smp_wmb(); 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds else { 7501da177e4SLinus Torvalds /* grow the key list */ 7511da177e4SLinus Torvalds max = 4; 7521da177e4SLinus Torvalds if (klist) 7531da177e4SLinus Torvalds max += klist->maxkeys; 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds ret = -ENFILE; 75676d8aeabSDavid Howells if (max > 65535) 75776d8aeabSDavid Howells goto error3; 758a4014d8fSDavid Howells size = sizeof(*klist) + sizeof(struct key *) * max; 7591da177e4SLinus Torvalds if (size > PAGE_SIZE) 7601da177e4SLinus Torvalds goto error3; 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds ret = -ENOMEM; 7631da177e4SLinus Torvalds nklist = kmalloc(size, GFP_KERNEL); 7641da177e4SLinus Torvalds if (!nklist) 7651da177e4SLinus Torvalds goto error3; 7661da177e4SLinus Torvalds nklist->maxkeys = max; 7671da177e4SLinus Torvalds nklist->nkeys = 0; 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds if (klist) { 7701da177e4SLinus Torvalds nklist->nkeys = klist->nkeys; 7711da177e4SLinus Torvalds memcpy(nklist->keys, 7721da177e4SLinus Torvalds klist->keys, 7731da177e4SLinus Torvalds sizeof(struct key *) * klist->nkeys); 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds /* add the key into the new space */ 7771da177e4SLinus Torvalds atomic_inc(&key->usage); 7781da177e4SLinus Torvalds nklist->keys[nklist->nkeys++] = key; 77976d8aeabSDavid Howells 78076d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds /* dispose of the old keyring list */ 78376d8aeabSDavid Howells if (klist) 78476d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_link_rcu_disposal); 7851da177e4SLinus Torvalds } 7861da177e4SLinus Torvalds 787cab8eb59SDavid Howells done: 788cab8eb59SDavid Howells ret = 0; 7891da177e4SLinus Torvalds error2: 7901da177e4SLinus Torvalds up_write(&keyring_serialise_link_sem); 7911da177e4SLinus Torvalds error: 7921da177e4SLinus Torvalds return ret; 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds error3: 7951da177e4SLinus Torvalds /* undo the quota changes */ 7961da177e4SLinus Torvalds key_payload_reserve(keyring, 7971da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 7981da177e4SLinus Torvalds goto error2; 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds } /* end __key_link() */ 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds /*****************************************************************************/ 8031da177e4SLinus Torvalds /* 8041da177e4SLinus Torvalds * link a key to a keyring 8051da177e4SLinus Torvalds */ 8061da177e4SLinus Torvalds int key_link(struct key *keyring, struct key *key) 8071da177e4SLinus Torvalds { 8081da177e4SLinus Torvalds int ret; 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds key_check(keyring); 8111da177e4SLinus Torvalds key_check(key); 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds down_write(&keyring->sem); 8141da177e4SLinus Torvalds ret = __key_link(keyring, key); 8151da177e4SLinus Torvalds up_write(&keyring->sem); 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds return ret; 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds } /* end key_link() */ 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds EXPORT_SYMBOL(key_link); 8221da177e4SLinus Torvalds 8231da177e4SLinus Torvalds /*****************************************************************************/ 8241da177e4SLinus Torvalds /* 8251da177e4SLinus Torvalds * unlink the first link to a key from a keyring 8261da177e4SLinus Torvalds */ 8271da177e4SLinus Torvalds int key_unlink(struct key *keyring, struct key *key) 8281da177e4SLinus Torvalds { 82976d8aeabSDavid Howells struct keyring_list *klist, *nklist; 8301da177e4SLinus Torvalds int loop, ret; 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds key_check(keyring); 8331da177e4SLinus Torvalds key_check(key); 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds ret = -ENOTDIR; 8361da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 8371da177e4SLinus Torvalds goto error; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds down_write(&keyring->sem); 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 8421da177e4SLinus Torvalds if (klist) { 8431da177e4SLinus Torvalds /* search the keyring for the key */ 8441da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) 8451da177e4SLinus Torvalds if (klist->keys[loop] == key) 8461da177e4SLinus Torvalds goto key_is_present; 8471da177e4SLinus Torvalds } 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds up_write(&keyring->sem); 8501da177e4SLinus Torvalds ret = -ENOENT; 8511da177e4SLinus Torvalds goto error; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds key_is_present: 85476d8aeabSDavid Howells /* we need to copy the key list for RCU purposes */ 855a4014d8fSDavid Howells nklist = kmalloc(sizeof(*klist) + 856a4014d8fSDavid Howells sizeof(struct key *) * klist->maxkeys, 85776d8aeabSDavid Howells GFP_KERNEL); 85876d8aeabSDavid Howells if (!nklist) 85976d8aeabSDavid Howells goto nomem; 86076d8aeabSDavid Howells nklist->maxkeys = klist->maxkeys; 86176d8aeabSDavid Howells nklist->nkeys = klist->nkeys - 1; 86276d8aeabSDavid Howells 86376d8aeabSDavid Howells if (loop > 0) 86476d8aeabSDavid Howells memcpy(&nklist->keys[0], 86576d8aeabSDavid Howells &klist->keys[0], 866a4014d8fSDavid Howells loop * sizeof(struct key *)); 86776d8aeabSDavid Howells 86876d8aeabSDavid Howells if (loop < nklist->nkeys) 86976d8aeabSDavid Howells memcpy(&nklist->keys[loop], 87076d8aeabSDavid Howells &klist->keys[loop + 1], 871a4014d8fSDavid Howells (nklist->nkeys - loop) * sizeof(struct key *)); 87276d8aeabSDavid Howells 8731da177e4SLinus Torvalds /* adjust the user's quota */ 8741da177e4SLinus Torvalds key_payload_reserve(keyring, 8751da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 8761da177e4SLinus Torvalds 87776d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds up_write(&keyring->sem); 88076d8aeabSDavid Howells 88176d8aeabSDavid Howells /* schedule for later cleanup */ 88276d8aeabSDavid Howells klist->delkey = loop; 88376d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 88476d8aeabSDavid Howells 8851da177e4SLinus Torvalds ret = 0; 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds error: 8881da177e4SLinus Torvalds return ret; 88976d8aeabSDavid Howells nomem: 89076d8aeabSDavid Howells ret = -ENOMEM; 89176d8aeabSDavid Howells up_write(&keyring->sem); 89276d8aeabSDavid Howells goto error; 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds } /* end key_unlink() */ 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds EXPORT_SYMBOL(key_unlink); 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds /*****************************************************************************/ 8991da177e4SLinus Torvalds /* 90076d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period, releasing the keys it 90176d8aeabSDavid Howells * links to 90276d8aeabSDavid Howells */ 90376d8aeabSDavid Howells static void keyring_clear_rcu_disposal(struct rcu_head *rcu) 90476d8aeabSDavid Howells { 90576d8aeabSDavid Howells struct keyring_list *klist; 90676d8aeabSDavid Howells int loop; 90776d8aeabSDavid Howells 90876d8aeabSDavid Howells klist = container_of(rcu, struct keyring_list, rcu); 90976d8aeabSDavid Howells 91076d8aeabSDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 91176d8aeabSDavid Howells key_put(klist->keys[loop]); 91276d8aeabSDavid Howells 91376d8aeabSDavid Howells kfree(klist); 91476d8aeabSDavid Howells 91576d8aeabSDavid Howells } /* end keyring_clear_rcu_disposal() */ 91676d8aeabSDavid Howells 91776d8aeabSDavid Howells /*****************************************************************************/ 91876d8aeabSDavid Howells /* 9191da177e4SLinus Torvalds * clear the specified process keyring 9201da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CLEAR) 9211da177e4SLinus Torvalds */ 9221da177e4SLinus Torvalds int keyring_clear(struct key *keyring) 9231da177e4SLinus Torvalds { 9241da177e4SLinus Torvalds struct keyring_list *klist; 92576d8aeabSDavid Howells int ret; 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds ret = -ENOTDIR; 9281da177e4SLinus Torvalds if (keyring->type == &key_type_keyring) { 9291da177e4SLinus Torvalds /* detach the pointer block with the locks held */ 9301da177e4SLinus Torvalds down_write(&keyring->sem); 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds klist = keyring->payload.subscriptions; 9331da177e4SLinus Torvalds if (klist) { 9341da177e4SLinus Torvalds /* adjust the quota */ 9351da177e4SLinus Torvalds key_payload_reserve(keyring, 9361da177e4SLinus Torvalds sizeof(struct keyring_list)); 9371da177e4SLinus Torvalds 93876d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, 93976d8aeabSDavid Howells NULL); 9401da177e4SLinus Torvalds } 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds up_write(&keyring->sem); 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* free the keys after the locks have been dropped */ 94576d8aeabSDavid Howells if (klist) 94676d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds ret = 0; 9491da177e4SLinus Torvalds } 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds return ret; 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds } /* end keyring_clear() */ 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_clear); 956