169664cf1SDavid Howells /* Keyring handling 21da177e4SLinus Torvalds * 369664cf1SDavid Howells * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. 41da177e4SLinus Torvalds * Written by David Howells (dhowells@redhat.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 91da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 121da177e4SLinus Torvalds #include <linux/module.h> 131da177e4SLinus Torvalds #include <linux/init.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 1629db9190SDavid Howells #include <linux/security.h> 171da177e4SLinus Torvalds #include <linux/seq_file.h> 181da177e4SLinus Torvalds #include <linux/err.h> 19e9e349b0SDavid Howells #include <keys/keyring-type.h> 20512ea3bcSChihau Chau #include <linux/uaccess.h> 211da177e4SLinus Torvalds #include "internal.h" 221da177e4SLinus Torvalds 23f0641cbaSDavid Howells #define rcu_dereference_locked_keyring(keyring) \ 24f0641cbaSDavid Howells (rcu_dereference_protected( \ 25f0641cbaSDavid Howells (keyring)->payload.subscriptions, \ 26f0641cbaSDavid Howells rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) 27f0641cbaSDavid Howells 281da177e4SLinus Torvalds /* 291da177e4SLinus Torvalds * when plumbing the depths of the key tree, this sets a hard limit set on how 301da177e4SLinus Torvalds * deep we're willing to go 311da177e4SLinus Torvalds */ 321da177e4SLinus Torvalds #define KEYRING_SEARCH_MAX_DEPTH 6 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* 351da177e4SLinus Torvalds * we keep all named keyrings in a hash to speed looking them up 361da177e4SLinus Torvalds */ 371da177e4SLinus Torvalds #define KEYRING_NAME_HASH_SIZE (1 << 5) 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static struct list_head keyring_name_hash[KEYRING_NAME_HASH_SIZE]; 401da177e4SLinus Torvalds static DEFINE_RWLOCK(keyring_name_lock); 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds static inline unsigned keyring_hash(const char *desc) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds unsigned bucket = 0; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds for (; *desc; desc++) 471da177e4SLinus Torvalds bucket += (unsigned char)*desc; 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds return bucket & (KEYRING_NAME_HASH_SIZE - 1); 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds /* 531da177e4SLinus Torvalds * the keyring type definition 541da177e4SLinus Torvalds */ 551da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 561da177e4SLinus Torvalds const void *data, size_t datalen); 571da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *criterion); 5831204ed9SDavid Howells static void keyring_revoke(struct key *keyring); 591da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring); 601da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m); 611da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 621da177e4SLinus Torvalds char __user *buffer, size_t buflen); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds struct key_type key_type_keyring = { 651da177e4SLinus Torvalds .name = "keyring", 661da177e4SLinus Torvalds .def_datalen = sizeof(struct keyring_list), 671da177e4SLinus Torvalds .instantiate = keyring_instantiate, 681da177e4SLinus Torvalds .match = keyring_match, 6931204ed9SDavid Howells .revoke = keyring_revoke, 701da177e4SLinus Torvalds .destroy = keyring_destroy, 711da177e4SLinus Torvalds .describe = keyring_describe, 721da177e4SLinus Torvalds .read = keyring_read, 731da177e4SLinus Torvalds }; 741da177e4SLinus Torvalds 757318226eSDavid Howells EXPORT_SYMBOL(key_type_keyring); 767318226eSDavid Howells 771da177e4SLinus Torvalds /* 781da177e4SLinus Torvalds * semaphore to serialise link/link calls to prevent two link calls in parallel 791da177e4SLinus Torvalds * introducing a cycle 801da177e4SLinus Torvalds */ 811ae8f407SAdrian Bunk static DECLARE_RWSEM(keyring_serialise_link_sem); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* 841da177e4SLinus Torvalds * publish the name of a keyring so that it can be found by name (if it has 851da177e4SLinus Torvalds * one) 861da177e4SLinus Torvalds */ 8769664cf1SDavid Howells static void keyring_publish_name(struct key *keyring) 881da177e4SLinus Torvalds { 891da177e4SLinus Torvalds int bucket; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds if (keyring->description) { 921da177e4SLinus Torvalds bucket = keyring_hash(keyring->description); 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds write_lock(&keyring_name_lock); 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds if (!keyring_name_hash[bucket].next) 971da177e4SLinus Torvalds INIT_LIST_HEAD(&keyring_name_hash[bucket]); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds list_add_tail(&keyring->type_data.link, 1001da177e4SLinus Torvalds &keyring_name_hash[bucket]); 1011da177e4SLinus Torvalds 1021da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 1031da177e4SLinus Torvalds } 104*a8b17ed0SDavid Howells } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* 1071da177e4SLinus Torvalds * initialise a keyring 1081da177e4SLinus Torvalds * - we object if we were given any data 1091da177e4SLinus Torvalds */ 1101da177e4SLinus Torvalds static int keyring_instantiate(struct key *keyring, 1111da177e4SLinus Torvalds const void *data, size_t datalen) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds int ret; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds ret = -EINVAL; 1161da177e4SLinus Torvalds if (datalen == 0) { 1171da177e4SLinus Torvalds /* make the keyring available by name if it has one */ 1181da177e4SLinus Torvalds keyring_publish_name(keyring); 1191da177e4SLinus Torvalds ret = 0; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds return ret; 123*a8b17ed0SDavid Howells } 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* 1261da177e4SLinus Torvalds * match keyrings on their name 1271da177e4SLinus Torvalds */ 1281da177e4SLinus Torvalds static int keyring_match(const struct key *keyring, const void *description) 1291da177e4SLinus Torvalds { 1301da177e4SLinus Torvalds return keyring->description && 1311da177e4SLinus Torvalds strcmp(keyring->description, description) == 0; 132*a8b17ed0SDavid Howells } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds /* 1351da177e4SLinus Torvalds * dispose of the data dangling from the corpse of a keyring 1361da177e4SLinus Torvalds */ 1371da177e4SLinus Torvalds static void keyring_destroy(struct key *keyring) 1381da177e4SLinus Torvalds { 1391da177e4SLinus Torvalds struct keyring_list *klist; 1401da177e4SLinus Torvalds int loop; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds if (keyring->description) { 1431da177e4SLinus Torvalds write_lock(&keyring_name_lock); 14494efe72fSDavid Howells 14594efe72fSDavid Howells if (keyring->type_data.link.next != NULL && 14694efe72fSDavid Howells !list_empty(&keyring->type_data.link)) 1471da177e4SLinus Torvalds list_del(&keyring->type_data.link); 14894efe72fSDavid Howells 1491da177e4SLinus Torvalds write_unlock(&keyring_name_lock); 1501da177e4SLinus Torvalds } 1511da177e4SLinus Torvalds 152e7b0a61bSPaul E. McKenney klist = rcu_dereference_check(keyring->payload.subscriptions, 153e7b0a61bSPaul E. McKenney rcu_read_lock_held() || 154e7b0a61bSPaul E. McKenney atomic_read(&keyring->usage) == 0); 1551da177e4SLinus Torvalds if (klist) { 1561da177e4SLinus Torvalds for (loop = klist->nkeys - 1; loop >= 0; loop--) 1571da177e4SLinus Torvalds key_put(klist->keys[loop]); 1581da177e4SLinus Torvalds kfree(klist); 1591da177e4SLinus Torvalds } 160*a8b17ed0SDavid Howells } 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds /* 1631da177e4SLinus Torvalds * describe the keyring 1641da177e4SLinus Torvalds */ 1651da177e4SLinus Torvalds static void keyring_describe(const struct key *keyring, struct seq_file *m) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds struct keyring_list *klist; 1681da177e4SLinus Torvalds 169c8563473Swzt.wzt@gmail.com if (keyring->description) 1701da177e4SLinus Torvalds seq_puts(m, keyring->description); 171c8563473Swzt.wzt@gmail.com else 1721da177e4SLinus Torvalds seq_puts(m, "[anon]"); 1731da177e4SLinus Torvalds 17476d8aeabSDavid Howells rcu_read_lock(); 17576d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 1761da177e4SLinus Torvalds if (klist) 1771da177e4SLinus Torvalds seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); 1781da177e4SLinus Torvalds else 1791da177e4SLinus Torvalds seq_puts(m, ": empty"); 18076d8aeabSDavid Howells rcu_read_unlock(); 181*a8b17ed0SDavid Howells } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds /* 1841da177e4SLinus Torvalds * read a list of key IDs from the keyring's contents 18576d8aeabSDavid Howells * - the keyring's semaphore is read-locked 1861da177e4SLinus Torvalds */ 1871da177e4SLinus Torvalds static long keyring_read(const struct key *keyring, 1881da177e4SLinus Torvalds char __user *buffer, size_t buflen) 1891da177e4SLinus Torvalds { 1901da177e4SLinus Torvalds struct keyring_list *klist; 1911da177e4SLinus Torvalds struct key *key; 1921da177e4SLinus Torvalds size_t qty, tmp; 1931da177e4SLinus Torvalds int loop, ret; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds ret = 0; 196f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 1971da177e4SLinus Torvalds if (klist) { 1981da177e4SLinus Torvalds /* calculate how much data we could return */ 1991da177e4SLinus Torvalds qty = klist->nkeys * sizeof(key_serial_t); 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds if (buffer && buflen > 0) { 2021da177e4SLinus Torvalds if (buflen > qty) 2031da177e4SLinus Torvalds buflen = qty; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds /* copy the IDs of the subscribed keys into the 2061da177e4SLinus Torvalds * buffer */ 2071da177e4SLinus Torvalds ret = -EFAULT; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 2101da177e4SLinus Torvalds key = klist->keys[loop]; 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds tmp = sizeof(key_serial_t); 2131da177e4SLinus Torvalds if (tmp > buflen) 2141da177e4SLinus Torvalds tmp = buflen; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds if (copy_to_user(buffer, 2171da177e4SLinus Torvalds &key->serial, 2181da177e4SLinus Torvalds tmp) != 0) 2191da177e4SLinus Torvalds goto error; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds buflen -= tmp; 2221da177e4SLinus Torvalds if (buflen == 0) 2231da177e4SLinus Torvalds break; 2241da177e4SLinus Torvalds buffer += tmp; 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds ret = qty; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds error: 2321da177e4SLinus Torvalds return ret; 233*a8b17ed0SDavid Howells } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* 2361da177e4SLinus Torvalds * allocate a keyring and link into the destination keyring 2371da177e4SLinus Torvalds */ 2381da177e4SLinus Torvalds struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, 239d84f4f99SDavid Howells const struct cred *cred, unsigned long flags, 240d720024eSMichael LeMay struct key *dest) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds struct key *keyring; 2431da177e4SLinus Torvalds int ret; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds keyring = key_alloc(&key_type_keyring, description, 246d84f4f99SDavid Howells uid, gid, cred, 24729db9190SDavid Howells (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, 2487e047ef5SDavid Howells flags); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds if (!IS_ERR(keyring)) { 2513e30148cSDavid Howells ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); 2521da177e4SLinus Torvalds if (ret < 0) { 2531da177e4SLinus Torvalds key_put(keyring); 2541da177e4SLinus Torvalds keyring = ERR_PTR(ret); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds return keyring; 259*a8b17ed0SDavid Howells } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /* 2621da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 2631da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 2641da177e4SLinus Torvalds * - we only find keys on which we have search permission 2651da177e4SLinus Torvalds * - we use the supplied match function to see if the description (or other 2661da177e4SLinus Torvalds * feature of interest) matches 2673e30148cSDavid Howells * - we rely on RCU to prevent the keyring lists from disappearing on us 2681da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 2691da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 270664cceb0SDavid Howells * - we propagate the possession attribute from the keyring ref to the key ref 2711da177e4SLinus Torvalds */ 272664cceb0SDavid Howells key_ref_t keyring_search_aux(key_ref_t keyring_ref, 273d84f4f99SDavid Howells const struct cred *cred, 2741da177e4SLinus Torvalds struct key_type *type, 2751da177e4SLinus Torvalds const void *description, 2761da177e4SLinus Torvalds key_match_func_t match) 2771da177e4SLinus Torvalds { 2781da177e4SLinus Torvalds struct { 27976d8aeabSDavid Howells struct keyring_list *keylist; 2801da177e4SLinus Torvalds int kix; 2811da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds struct keyring_list *keylist; 2841da177e4SLinus Torvalds struct timespec now; 285dceba994SKevin Coffman unsigned long possessed, kflags; 286664cceb0SDavid Howells struct key *keyring, *key; 287664cceb0SDavid Howells key_ref_t key_ref; 2881da177e4SLinus Torvalds long err; 28976d8aeabSDavid Howells int sp, kix; 2901da177e4SLinus Torvalds 291664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 292664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 2931da177e4SLinus Torvalds key_check(keyring); 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* top keyring must have search permission to begin the search */ 296d84f4f99SDavid Howells err = key_task_permission(keyring_ref, cred, KEY_SEARCH); 29729db9190SDavid Howells if (err < 0) { 29829db9190SDavid Howells key_ref = ERR_PTR(err); 2991da177e4SLinus Torvalds goto error; 30029db9190SDavid Howells } 3011da177e4SLinus Torvalds 302664cceb0SDavid Howells key_ref = ERR_PTR(-ENOTDIR); 3031da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 3041da177e4SLinus Torvalds goto error; 3051da177e4SLinus Torvalds 306664cceb0SDavid Howells rcu_read_lock(); 307664cceb0SDavid Howells 3081da177e4SLinus Torvalds now = current_kernel_time(); 3091da177e4SLinus Torvalds err = -EAGAIN; 3101da177e4SLinus Torvalds sp = 0; 3111da177e4SLinus Torvalds 312dceba994SKevin Coffman /* firstly we should check to see if this top-level keyring is what we 313dceba994SKevin Coffman * are looking for */ 314dceba994SKevin Coffman key_ref = ERR_PTR(-EAGAIN); 315dceba994SKevin Coffman kflags = keyring->flags; 316dceba994SKevin Coffman if (keyring->type == type && match(keyring, description)) { 317dceba994SKevin Coffman key = keyring; 318dceba994SKevin Coffman 319dceba994SKevin Coffman /* check it isn't negative and hasn't expired or been 320dceba994SKevin Coffman * revoked */ 321dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_REVOKED)) 322dceba994SKevin Coffman goto error_2; 323dceba994SKevin Coffman if (key->expiry && now.tv_sec >= key->expiry) 324dceba994SKevin Coffman goto error_2; 325dceba994SKevin Coffman key_ref = ERR_PTR(-ENOKEY); 326dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_NEGATIVE)) 327dceba994SKevin Coffman goto error_2; 328dceba994SKevin Coffman goto found; 329dceba994SKevin Coffman } 330dceba994SKevin Coffman 331dceba994SKevin Coffman /* otherwise, the top keyring must not be revoked, expired, or 332dceba994SKevin Coffman * negatively instantiated if we are to search it */ 333dceba994SKevin Coffman key_ref = ERR_PTR(-EAGAIN); 334dceba994SKevin Coffman if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || 335dceba994SKevin Coffman (keyring->expiry && now.tv_sec >= keyring->expiry)) 336dceba994SKevin Coffman goto error_2; 337dceba994SKevin Coffman 3381da177e4SLinus Torvalds /* start processing a new keyring */ 3391da177e4SLinus Torvalds descend: 34076d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 3411da177e4SLinus Torvalds goto not_this_keyring; 3421da177e4SLinus Torvalds 34376d8aeabSDavid Howells keylist = rcu_dereference(keyring->payload.subscriptions); 3441da177e4SLinus Torvalds if (!keylist) 3451da177e4SLinus Torvalds goto not_this_keyring; 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds /* iterate through the keys in this keyring first */ 3481da177e4SLinus Torvalds for (kix = 0; kix < keylist->nkeys; kix++) { 3491da177e4SLinus Torvalds key = keylist->keys[kix]; 350dceba994SKevin Coffman kflags = key->flags; 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds /* ignore keys not of this type */ 3531da177e4SLinus Torvalds if (key->type != type) 3541da177e4SLinus Torvalds continue; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds /* skip revoked keys and expired keys */ 357dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_REVOKED)) 3581da177e4SLinus Torvalds continue; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds if (key->expiry && now.tv_sec >= key->expiry) 3611da177e4SLinus Torvalds continue; 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds /* keys that don't match */ 3641da177e4SLinus Torvalds if (!match(key, description)) 3651da177e4SLinus Torvalds continue; 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds /* key must have search permissions */ 36829db9190SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 369d84f4f99SDavid Howells cred, KEY_SEARCH) < 0) 3701da177e4SLinus Torvalds continue; 3711da177e4SLinus Torvalds 372dceba994SKevin Coffman /* we set a different error code if we pass a negative key */ 373dceba994SKevin Coffman if (kflags & (1 << KEY_FLAG_NEGATIVE)) { 3741da177e4SLinus Torvalds err = -ENOKEY; 3751da177e4SLinus Torvalds continue; 3761da177e4SLinus Torvalds } 3771da177e4SLinus Torvalds 3781da177e4SLinus Torvalds goto found; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds /* search through the keyrings nested in this one */ 3821da177e4SLinus Torvalds kix = 0; 3831da177e4SLinus Torvalds ascend: 38476d8aeabSDavid Howells for (; kix < keylist->nkeys; kix++) { 3851da177e4SLinus Torvalds key = keylist->keys[kix]; 3861da177e4SLinus Torvalds if (key->type != &key_type_keyring) 38776d8aeabSDavid Howells continue; 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* recursively search nested keyrings 3901da177e4SLinus Torvalds * - only search keyrings for which we have search permission 3911da177e4SLinus Torvalds */ 3921da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 39376d8aeabSDavid Howells continue; 3941da177e4SLinus Torvalds 3950f6ed7c2SDavid Howells if (key_task_permission(make_key_ref(key, possessed), 396d84f4f99SDavid Howells cred, KEY_SEARCH) < 0) 39776d8aeabSDavid Howells continue; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds /* stack the current position */ 40076d8aeabSDavid Howells stack[sp].keylist = keylist; 4011da177e4SLinus Torvalds stack[sp].kix = kix; 4021da177e4SLinus Torvalds sp++; 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds /* begin again with the new keyring */ 4051da177e4SLinus Torvalds keyring = key; 4061da177e4SLinus Torvalds goto descend; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 4101da177e4SLinus Torvalds * matching key */ 4111da177e4SLinus Torvalds not_this_keyring: 4121da177e4SLinus Torvalds if (sp > 0) { 4131da177e4SLinus Torvalds /* resume the processing of a keyring higher up in the tree */ 4141da177e4SLinus Torvalds sp--; 41576d8aeabSDavid Howells keylist = stack[sp].keylist; 4161da177e4SLinus Torvalds kix = stack[sp].kix + 1; 4171da177e4SLinus Torvalds goto ascend; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420664cceb0SDavid Howells key_ref = ERR_PTR(err); 421664cceb0SDavid Howells goto error_2; 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds /* we found a viable match */ 4241da177e4SLinus Torvalds found: 4251da177e4SLinus Torvalds atomic_inc(&key->usage); 4261da177e4SLinus Torvalds key_check(key); 427664cceb0SDavid Howells key_ref = make_key_ref(key, possessed); 428664cceb0SDavid Howells error_2: 42976d8aeabSDavid Howells rcu_read_unlock(); 430664cceb0SDavid Howells error: 431664cceb0SDavid Howells return key_ref; 432*a8b17ed0SDavid Howells } 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds /* 4351da177e4SLinus Torvalds * search the supplied keyring tree for a key that matches the criterion 4361da177e4SLinus Torvalds * - perform a breadth-then-depth search up to the prescribed limit 4371da177e4SLinus Torvalds * - we only find keys on which we have search permission 4381da177e4SLinus Torvalds * - we readlock the keyrings as we search down the tree 4391da177e4SLinus Torvalds * - we return -EAGAIN if we didn't find any matching key 4401da177e4SLinus Torvalds * - we return -ENOKEY if we only found negative matching keys 4411da177e4SLinus Torvalds */ 442664cceb0SDavid Howells key_ref_t keyring_search(key_ref_t keyring, 4431da177e4SLinus Torvalds struct key_type *type, 4441da177e4SLinus Torvalds const char *description) 4451da177e4SLinus Torvalds { 4463e30148cSDavid Howells if (!type->match) 4473e30148cSDavid Howells return ERR_PTR(-ENOKEY); 4483e30148cSDavid Howells 449d84f4f99SDavid Howells return keyring_search_aux(keyring, current->cred, 4503e30148cSDavid Howells type, description, type->match); 451*a8b17ed0SDavid Howells } 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_search); 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds /* 4561da177e4SLinus Torvalds * search the given keyring only (no recursion) 4571da177e4SLinus Torvalds * - keyring must be locked by caller 458c3a9d654SDavid Howells * - caller must guarantee that the keyring is a keyring 4591da177e4SLinus Torvalds */ 460664cceb0SDavid Howells key_ref_t __keyring_search_one(key_ref_t keyring_ref, 4611da177e4SLinus Torvalds const struct key_type *ktype, 4621da177e4SLinus Torvalds const char *description, 4631da177e4SLinus Torvalds key_perm_t perm) 4641da177e4SLinus Torvalds { 4651da177e4SLinus Torvalds struct keyring_list *klist; 466664cceb0SDavid Howells unsigned long possessed; 467664cceb0SDavid Howells struct key *keyring, *key; 4681da177e4SLinus Torvalds int loop; 4691da177e4SLinus Torvalds 470664cceb0SDavid Howells keyring = key_ref_to_ptr(keyring_ref); 471664cceb0SDavid Howells possessed = is_key_possessed(keyring_ref); 472664cceb0SDavid Howells 47376d8aeabSDavid Howells rcu_read_lock(); 47476d8aeabSDavid Howells 47576d8aeabSDavid Howells klist = rcu_dereference(keyring->payload.subscriptions); 4761da177e4SLinus Torvalds if (klist) { 4771da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) { 4781da177e4SLinus Torvalds key = klist->keys[loop]; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds if (key->type == ktype && 4813e30148cSDavid Howells (!key->type->match || 4823e30148cSDavid Howells key->type->match(key, description)) && 483664cceb0SDavid Howells key_permission(make_key_ref(key, possessed), 484db1d1d57SDavid Howells perm) == 0 && 48576d8aeabSDavid Howells !test_bit(KEY_FLAG_REVOKED, &key->flags) 4861da177e4SLinus Torvalds ) 4871da177e4SLinus Torvalds goto found; 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 491664cceb0SDavid Howells rcu_read_unlock(); 492664cceb0SDavid Howells return ERR_PTR(-ENOKEY); 4931da177e4SLinus Torvalds 4941da177e4SLinus Torvalds found: 4951da177e4SLinus Torvalds atomic_inc(&key->usage); 49676d8aeabSDavid Howells rcu_read_unlock(); 497664cceb0SDavid Howells return make_key_ref(key, possessed); 498*a8b17ed0SDavid Howells } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds /* 5011da177e4SLinus Torvalds * find a keyring with the specified name 5021da177e4SLinus Torvalds * - all named keyrings are searched 50369664cf1SDavid Howells * - normally only finds keyrings with search permission for the current process 5041da177e4SLinus Torvalds */ 50569664cf1SDavid Howells struct key *find_keyring_by_name(const char *name, bool skip_perm_check) 5061da177e4SLinus Torvalds { 5071da177e4SLinus Torvalds struct key *keyring; 5081da177e4SLinus Torvalds int bucket; 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds if (!name) 511cea7daa3SToshiyuki Okajima return ERR_PTR(-EINVAL); 5121da177e4SLinus Torvalds 5131da177e4SLinus Torvalds bucket = keyring_hash(name); 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds read_lock(&keyring_name_lock); 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds if (keyring_name_hash[bucket].next) { 5181da177e4SLinus Torvalds /* search this hash bucket for a keyring with a matching name 5191da177e4SLinus Torvalds * that's readable and that hasn't been revoked */ 5201da177e4SLinus Torvalds list_for_each_entry(keyring, 5211da177e4SLinus Torvalds &keyring_name_hash[bucket], 5221da177e4SLinus Torvalds type_data.link 5231da177e4SLinus Torvalds ) { 5242ea190d0SSerge E. Hallyn if (keyring->user->user_ns != current_user_ns()) 5252ea190d0SSerge E. Hallyn continue; 5262ea190d0SSerge E. Hallyn 52776d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 5281da177e4SLinus Torvalds continue; 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds if (strcmp(keyring->description, name) != 0) 5311da177e4SLinus Torvalds continue; 5321da177e4SLinus Torvalds 53369664cf1SDavid Howells if (!skip_perm_check && 53469664cf1SDavid Howells key_permission(make_key_ref(keyring, 0), 53529db9190SDavid Howells KEY_SEARCH) < 0) 5361da177e4SLinus Torvalds continue; 5371da177e4SLinus Torvalds 538cea7daa3SToshiyuki Okajima /* we've got a match but we might end up racing with 539cea7daa3SToshiyuki Okajima * key_cleanup() if the keyring is currently 'dead' 540cea7daa3SToshiyuki Okajima * (ie. it has a zero usage count) */ 541cea7daa3SToshiyuki Okajima if (!atomic_inc_not_zero(&keyring->usage)) 542cea7daa3SToshiyuki Okajima continue; 543cea7daa3SToshiyuki Okajima goto out; 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds keyring = ERR_PTR(-ENOKEY); 548cea7daa3SToshiyuki Okajima out: 549cea7daa3SToshiyuki Okajima read_unlock(&keyring_name_lock); 5501da177e4SLinus Torvalds return keyring; 551*a8b17ed0SDavid Howells } 5521da177e4SLinus Torvalds 5531da177e4SLinus Torvalds /* 5541da177e4SLinus Torvalds * see if a cycle will will be created by inserting acyclic tree B in acyclic 5551da177e4SLinus Torvalds * tree A at the topmost level (ie: as a direct child of A) 5561da177e4SLinus Torvalds * - since we are adding B to A at the top level, checking for cycles should 5571da177e4SLinus Torvalds * just be a matter of seeing if node A is somewhere in tree B 5581da177e4SLinus Torvalds */ 5591da177e4SLinus Torvalds static int keyring_detect_cycle(struct key *A, struct key *B) 5601da177e4SLinus Torvalds { 5611da177e4SLinus Torvalds struct { 56276d8aeabSDavid Howells struct keyring_list *keylist; 5631da177e4SLinus Torvalds int kix; 5641da177e4SLinus Torvalds } stack[KEYRING_SEARCH_MAX_DEPTH]; 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds struct keyring_list *keylist; 5671da177e4SLinus Torvalds struct key *subtree, *key; 5681da177e4SLinus Torvalds int sp, kix, ret; 5691da177e4SLinus Torvalds 57076d8aeabSDavid Howells rcu_read_lock(); 57176d8aeabSDavid Howells 5721da177e4SLinus Torvalds ret = -EDEADLK; 5731da177e4SLinus Torvalds if (A == B) 57476d8aeabSDavid Howells goto cycle_detected; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds subtree = B; 5771da177e4SLinus Torvalds sp = 0; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds /* start processing a new keyring */ 5801da177e4SLinus Torvalds descend: 58176d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) 5821da177e4SLinus Torvalds goto not_this_keyring; 5831da177e4SLinus Torvalds 58476d8aeabSDavid Howells keylist = rcu_dereference(subtree->payload.subscriptions); 5851da177e4SLinus Torvalds if (!keylist) 5861da177e4SLinus Torvalds goto not_this_keyring; 5871da177e4SLinus Torvalds kix = 0; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds ascend: 5901da177e4SLinus Torvalds /* iterate through the remaining keys in this keyring */ 5911da177e4SLinus Torvalds for (; kix < keylist->nkeys; kix++) { 5921da177e4SLinus Torvalds key = keylist->keys[kix]; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds if (key == A) 5951da177e4SLinus Torvalds goto cycle_detected; 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds /* recursively check nested keyrings */ 5981da177e4SLinus Torvalds if (key->type == &key_type_keyring) { 5991da177e4SLinus Torvalds if (sp >= KEYRING_SEARCH_MAX_DEPTH) 6001da177e4SLinus Torvalds goto too_deep; 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* stack the current position */ 60376d8aeabSDavid Howells stack[sp].keylist = keylist; 6041da177e4SLinus Torvalds stack[sp].kix = kix; 6051da177e4SLinus Torvalds sp++; 6061da177e4SLinus Torvalds 6071da177e4SLinus Torvalds /* begin again with the new keyring */ 6081da177e4SLinus Torvalds subtree = key; 6091da177e4SLinus Torvalds goto descend; 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds /* the keyring we're looking at was disqualified or didn't contain a 6141da177e4SLinus Torvalds * matching key */ 6151da177e4SLinus Torvalds not_this_keyring: 6161da177e4SLinus Torvalds if (sp > 0) { 6171da177e4SLinus Torvalds /* resume the checking of a keyring higher up in the tree */ 6181da177e4SLinus Torvalds sp--; 61976d8aeabSDavid Howells keylist = stack[sp].keylist; 6201da177e4SLinus Torvalds kix = stack[sp].kix + 1; 6211da177e4SLinus Torvalds goto ascend; 6221da177e4SLinus Torvalds } 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds ret = 0; /* no cycles detected */ 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds error: 62776d8aeabSDavid Howells rcu_read_unlock(); 6281da177e4SLinus Torvalds return ret; 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds too_deep: 6311da177e4SLinus Torvalds ret = -ELOOP; 63276d8aeabSDavid Howells goto error; 63376d8aeabSDavid Howells 6341da177e4SLinus Torvalds cycle_detected: 6351da177e4SLinus Torvalds ret = -EDEADLK; 6361da177e4SLinus Torvalds goto error; 637*a8b17ed0SDavid Howells } 6381da177e4SLinus Torvalds 63976d8aeabSDavid Howells /* 640cab8eb59SDavid Howells * dispose of a keyring list after the RCU grace period, freeing the unlinked 641cab8eb59SDavid Howells * key 642cab8eb59SDavid Howells */ 643cab8eb59SDavid Howells static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) 644cab8eb59SDavid Howells { 645cab8eb59SDavid Howells struct keyring_list *klist = 646cab8eb59SDavid Howells container_of(rcu, struct keyring_list, rcu); 647cab8eb59SDavid Howells 6484be929beSAlexey Dobriyan if (klist->delkey != USHRT_MAX) 649cab8eb59SDavid Howells key_put(klist->keys[klist->delkey]); 650cab8eb59SDavid Howells kfree(klist); 651f70e2e06SDavid Howells } 652cab8eb59SDavid Howells 653cab8eb59SDavid Howells /* 654f70e2e06SDavid Howells * preallocate memory so that a key can be linked into to a keyring 6551da177e4SLinus Torvalds */ 656f70e2e06SDavid Howells int __key_link_begin(struct key *keyring, const struct key_type *type, 657f70e2e06SDavid Howells const char *description, 658f70e2e06SDavid Howells struct keyring_list **_prealloc) 659f70e2e06SDavid Howells __acquires(&keyring->sem) 6601da177e4SLinus Torvalds { 6611da177e4SLinus Torvalds struct keyring_list *klist, *nklist; 6621da177e4SLinus Torvalds unsigned max; 6631da177e4SLinus Torvalds size_t size; 664cab8eb59SDavid Howells int loop, ret; 6651da177e4SLinus Torvalds 666f70e2e06SDavid Howells kenter("%d,%s,%s,", key_serial(keyring), type->name, description); 667f70e2e06SDavid Howells 668f70e2e06SDavid Howells if (keyring->type != &key_type_keyring) 669f70e2e06SDavid Howells return -ENOTDIR; 670f70e2e06SDavid Howells 671f70e2e06SDavid Howells down_write(&keyring->sem); 672f70e2e06SDavid Howells 6731da177e4SLinus Torvalds ret = -EKEYREVOKED; 67476d8aeabSDavid Howells if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) 675f70e2e06SDavid Howells goto error_krsem; 6761da177e4SLinus Torvalds 677f70e2e06SDavid Howells /* serialise link/link calls to prevent parallel calls causing a cycle 678f70e2e06SDavid Howells * when linking two keyring in opposite orders */ 679f70e2e06SDavid Howells if (type == &key_type_keyring) 6801da177e4SLinus Torvalds down_write(&keyring_serialise_link_sem); 6811da177e4SLinus Torvalds 682f70e2e06SDavid Howells klist = rcu_dereference_locked_keyring(keyring); 6831da177e4SLinus Torvalds 684cab8eb59SDavid Howells /* see if there's a matching key we can displace */ 685cab8eb59SDavid Howells if (klist && klist->nkeys > 0) { 686cab8eb59SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 687cab8eb59SDavid Howells if (klist->keys[loop]->type == type && 688cab8eb59SDavid Howells strcmp(klist->keys[loop]->description, 689f70e2e06SDavid Howells description) == 0 690cab8eb59SDavid Howells ) { 691f70e2e06SDavid Howells /* found a match - we'll replace this one with 692f70e2e06SDavid Howells * the new key */ 693cab8eb59SDavid Howells size = sizeof(struct key *) * klist->maxkeys; 694cab8eb59SDavid Howells size += sizeof(*klist); 695cab8eb59SDavid Howells BUG_ON(size > PAGE_SIZE); 696cab8eb59SDavid Howells 697cab8eb59SDavid Howells ret = -ENOMEM; 69848ad504eSEric Sesterhenn nklist = kmemdup(klist, size, GFP_KERNEL); 699cab8eb59SDavid Howells if (!nklist) 700f70e2e06SDavid Howells goto error_sem; 701cab8eb59SDavid Howells 702f70e2e06SDavid Howells /* note replacement slot */ 703f70e2e06SDavid Howells klist->delkey = nklist->delkey = loop; 704cab8eb59SDavid Howells goto done; 705cab8eb59SDavid Howells } 706cab8eb59SDavid Howells } 707cab8eb59SDavid Howells } 708cab8eb59SDavid Howells 7091da177e4SLinus Torvalds /* check that we aren't going to overrun the user's quota */ 7101da177e4SLinus Torvalds ret = key_payload_reserve(keyring, 7111da177e4SLinus Torvalds keyring->datalen + KEYQUOTA_LINK_BYTES); 7121da177e4SLinus Torvalds if (ret < 0) 713f70e2e06SDavid Howells goto error_sem; 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds if (klist && klist->nkeys < klist->maxkeys) { 716f70e2e06SDavid Howells /* there's sufficient slack space to append directly */ 717f70e2e06SDavid Howells nklist = NULL; 718512ea3bcSChihau Chau } else { 7191da177e4SLinus Torvalds /* grow the key list */ 7201da177e4SLinus Torvalds max = 4; 7211da177e4SLinus Torvalds if (klist) 7221da177e4SLinus Torvalds max += klist->maxkeys; 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds ret = -ENFILE; 7254be929beSAlexey Dobriyan if (max > USHRT_MAX - 1) 726f70e2e06SDavid Howells goto error_quota; 727a4014d8fSDavid Howells size = sizeof(*klist) + sizeof(struct key *) * max; 7281da177e4SLinus Torvalds if (size > PAGE_SIZE) 729f70e2e06SDavid Howells goto error_quota; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds ret = -ENOMEM; 7321da177e4SLinus Torvalds nklist = kmalloc(size, GFP_KERNEL); 7331da177e4SLinus Torvalds if (!nklist) 734f70e2e06SDavid Howells goto error_quota; 7351da177e4SLinus Torvalds 736f70e2e06SDavid Howells nklist->maxkeys = max; 7371da177e4SLinus Torvalds if (klist) { 738f70e2e06SDavid Howells memcpy(nklist->keys, klist->keys, 7391da177e4SLinus Torvalds sizeof(struct key *) * klist->nkeys); 740f70e2e06SDavid Howells nklist->delkey = klist->nkeys; 741f70e2e06SDavid Howells nklist->nkeys = klist->nkeys + 1; 7424be929beSAlexey Dobriyan klist->delkey = USHRT_MAX; 743f70e2e06SDavid Howells } else { 744f70e2e06SDavid Howells nklist->nkeys = 1; 745f70e2e06SDavid Howells nklist->delkey = 0; 7461da177e4SLinus Torvalds } 7471da177e4SLinus Torvalds 7481da177e4SLinus Torvalds /* add the key into the new space */ 749f70e2e06SDavid Howells nklist->keys[nklist->delkey] = NULL; 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds 752cab8eb59SDavid Howells done: 753f70e2e06SDavid Howells *_prealloc = nklist; 754f70e2e06SDavid Howells kleave(" = 0"); 755f70e2e06SDavid Howells return 0; 7561da177e4SLinus Torvalds 757f70e2e06SDavid Howells error_quota: 7581da177e4SLinus Torvalds /* undo the quota changes */ 7591da177e4SLinus Torvalds key_payload_reserve(keyring, 7601da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 761f70e2e06SDavid Howells error_sem: 762f70e2e06SDavid Howells if (type == &key_type_keyring) 763f70e2e06SDavid Howells up_write(&keyring_serialise_link_sem); 764f70e2e06SDavid Howells error_krsem: 765f70e2e06SDavid Howells up_write(&keyring->sem); 766f70e2e06SDavid Howells kleave(" = %d", ret); 767f70e2e06SDavid Howells return ret; 768f70e2e06SDavid Howells } 7691da177e4SLinus Torvalds 770f70e2e06SDavid Howells /* 771f70e2e06SDavid Howells * check already instantiated keys aren't going to be a problem 772f70e2e06SDavid Howells * - the caller must have called __key_link_begin() 773f70e2e06SDavid Howells * - don't need to call this for keys that were created since __key_link_begin() 774f70e2e06SDavid Howells * was called 775f70e2e06SDavid Howells */ 776f70e2e06SDavid Howells int __key_link_check_live_key(struct key *keyring, struct key *key) 777f70e2e06SDavid Howells { 778f70e2e06SDavid Howells if (key->type == &key_type_keyring) 779f70e2e06SDavid Howells /* check that we aren't going to create a cycle by linking one 780f70e2e06SDavid Howells * keyring to another */ 781f70e2e06SDavid Howells return keyring_detect_cycle(keyring, key); 782f70e2e06SDavid Howells return 0; 783f70e2e06SDavid Howells } 7841da177e4SLinus Torvalds 785f70e2e06SDavid Howells /* 786f70e2e06SDavid Howells * link a key into to a keyring 787f70e2e06SDavid Howells * - must be called with __key_link_begin() having being called 788f70e2e06SDavid Howells * - discard already extant link to matching key if there is one 789f70e2e06SDavid Howells */ 790f70e2e06SDavid Howells void __key_link(struct key *keyring, struct key *key, 791f70e2e06SDavid Howells struct keyring_list **_prealloc) 792f70e2e06SDavid Howells { 793f70e2e06SDavid Howells struct keyring_list *klist, *nklist; 794f70e2e06SDavid Howells 795f70e2e06SDavid Howells nklist = *_prealloc; 796f70e2e06SDavid Howells *_prealloc = NULL; 797f70e2e06SDavid Howells 798f70e2e06SDavid Howells kenter("%d,%d,%p", keyring->serial, key->serial, nklist); 799f70e2e06SDavid Howells 800f70e2e06SDavid Howells klist = rcu_dereference_protected(keyring->payload.subscriptions, 801f70e2e06SDavid Howells rwsem_is_locked(&keyring->sem)); 802f70e2e06SDavid Howells 803f70e2e06SDavid Howells atomic_inc(&key->usage); 804f70e2e06SDavid Howells 805f70e2e06SDavid Howells /* there's a matching key we can displace or an empty slot in a newly 806f70e2e06SDavid Howells * allocated list we can fill */ 807f70e2e06SDavid Howells if (nklist) { 808f70e2e06SDavid Howells kdebug("replace %hu/%hu/%hu", 809f70e2e06SDavid Howells nklist->delkey, nklist->nkeys, nklist->maxkeys); 810f70e2e06SDavid Howells 811f70e2e06SDavid Howells nklist->keys[nklist->delkey] = key; 812f70e2e06SDavid Howells 813f70e2e06SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 814f70e2e06SDavid Howells 815f70e2e06SDavid Howells /* dispose of the old keyring list and, if there was one, the 816f70e2e06SDavid Howells * displaced key */ 817f70e2e06SDavid Howells if (klist) { 818f70e2e06SDavid Howells kdebug("dispose %hu/%hu/%hu", 819f70e2e06SDavid Howells klist->delkey, klist->nkeys, klist->maxkeys); 820f70e2e06SDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 821f70e2e06SDavid Howells } 822f70e2e06SDavid Howells } else { 823f70e2e06SDavid Howells /* there's sufficient slack space to append directly */ 824f70e2e06SDavid Howells klist->keys[klist->nkeys] = key; 825f70e2e06SDavid Howells smp_wmb(); 826f70e2e06SDavid Howells klist->nkeys++; 827f70e2e06SDavid Howells } 828f70e2e06SDavid Howells } 829f70e2e06SDavid Howells 830f70e2e06SDavid Howells /* 831f70e2e06SDavid Howells * finish linking a key into to a keyring 832f70e2e06SDavid Howells * - must be called with __key_link_begin() having being called 833f70e2e06SDavid Howells */ 834f70e2e06SDavid Howells void __key_link_end(struct key *keyring, struct key_type *type, 835f70e2e06SDavid Howells struct keyring_list *prealloc) 836f70e2e06SDavid Howells __releases(&keyring->sem) 837f70e2e06SDavid Howells { 838f70e2e06SDavid Howells BUG_ON(type == NULL); 839f70e2e06SDavid Howells BUG_ON(type->name == NULL); 840f70e2e06SDavid Howells kenter("%d,%s,%p", keyring->serial, type->name, prealloc); 841f70e2e06SDavid Howells 842f70e2e06SDavid Howells if (type == &key_type_keyring) 843f70e2e06SDavid Howells up_write(&keyring_serialise_link_sem); 844f70e2e06SDavid Howells 845f70e2e06SDavid Howells if (prealloc) { 846f70e2e06SDavid Howells kfree(prealloc); 847f70e2e06SDavid Howells key_payload_reserve(keyring, 848f70e2e06SDavid Howells keyring->datalen - KEYQUOTA_LINK_BYTES); 849f70e2e06SDavid Howells } 850f70e2e06SDavid Howells up_write(&keyring->sem); 851f70e2e06SDavid Howells } 852f70e2e06SDavid Howells 8531da177e4SLinus Torvalds /* 8541da177e4SLinus Torvalds * link a key to a keyring 8551da177e4SLinus Torvalds */ 8561da177e4SLinus Torvalds int key_link(struct key *keyring, struct key *key) 8571da177e4SLinus Torvalds { 858f70e2e06SDavid Howells struct keyring_list *prealloc; 8591da177e4SLinus Torvalds int ret; 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds key_check(keyring); 8621da177e4SLinus Torvalds key_check(key); 8631da177e4SLinus Torvalds 864f70e2e06SDavid Howells ret = __key_link_begin(keyring, key->type, key->description, &prealloc); 865f70e2e06SDavid Howells if (ret == 0) { 866f70e2e06SDavid Howells ret = __key_link_check_live_key(keyring, key); 867f70e2e06SDavid Howells if (ret == 0) 868f70e2e06SDavid Howells __key_link(keyring, key, &prealloc); 869f70e2e06SDavid Howells __key_link_end(keyring, key->type, prealloc); 870f70e2e06SDavid Howells } 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds return ret; 873f70e2e06SDavid Howells } 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds EXPORT_SYMBOL(key_link); 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds /* 8781da177e4SLinus Torvalds * unlink the first link to a key from a keyring 8791da177e4SLinus Torvalds */ 8801da177e4SLinus Torvalds int key_unlink(struct key *keyring, struct key *key) 8811da177e4SLinus Torvalds { 88276d8aeabSDavid Howells struct keyring_list *klist, *nklist; 8831da177e4SLinus Torvalds int loop, ret; 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds key_check(keyring); 8861da177e4SLinus Torvalds key_check(key); 8871da177e4SLinus Torvalds 8881da177e4SLinus Torvalds ret = -ENOTDIR; 8891da177e4SLinus Torvalds if (keyring->type != &key_type_keyring) 8901da177e4SLinus Torvalds goto error; 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds down_write(&keyring->sem); 8931da177e4SLinus Torvalds 894f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 8951da177e4SLinus Torvalds if (klist) { 8961da177e4SLinus Torvalds /* search the keyring for the key */ 8971da177e4SLinus Torvalds for (loop = 0; loop < klist->nkeys; loop++) 8981da177e4SLinus Torvalds if (klist->keys[loop] == key) 8991da177e4SLinus Torvalds goto key_is_present; 9001da177e4SLinus Torvalds } 9011da177e4SLinus Torvalds 9021da177e4SLinus Torvalds up_write(&keyring->sem); 9031da177e4SLinus Torvalds ret = -ENOENT; 9041da177e4SLinus Torvalds goto error; 9051da177e4SLinus Torvalds 9061da177e4SLinus Torvalds key_is_present: 90776d8aeabSDavid Howells /* we need to copy the key list for RCU purposes */ 908a4014d8fSDavid Howells nklist = kmalloc(sizeof(*klist) + 909a4014d8fSDavid Howells sizeof(struct key *) * klist->maxkeys, 91076d8aeabSDavid Howells GFP_KERNEL); 91176d8aeabSDavid Howells if (!nklist) 91276d8aeabSDavid Howells goto nomem; 91376d8aeabSDavid Howells nklist->maxkeys = klist->maxkeys; 91476d8aeabSDavid Howells nklist->nkeys = klist->nkeys - 1; 91576d8aeabSDavid Howells 91676d8aeabSDavid Howells if (loop > 0) 91776d8aeabSDavid Howells memcpy(&nklist->keys[0], 91876d8aeabSDavid Howells &klist->keys[0], 919a4014d8fSDavid Howells loop * sizeof(struct key *)); 92076d8aeabSDavid Howells 92176d8aeabSDavid Howells if (loop < nklist->nkeys) 92276d8aeabSDavid Howells memcpy(&nklist->keys[loop], 92376d8aeabSDavid Howells &klist->keys[loop + 1], 924a4014d8fSDavid Howells (nklist->nkeys - loop) * sizeof(struct key *)); 92576d8aeabSDavid Howells 9261da177e4SLinus Torvalds /* adjust the user's quota */ 9271da177e4SLinus Torvalds key_payload_reserve(keyring, 9281da177e4SLinus Torvalds keyring->datalen - KEYQUOTA_LINK_BYTES); 9291da177e4SLinus Torvalds 93076d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, nklist); 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds up_write(&keyring->sem); 93376d8aeabSDavid Howells 93476d8aeabSDavid Howells /* schedule for later cleanup */ 93576d8aeabSDavid Howells klist->delkey = loop; 93676d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); 93776d8aeabSDavid Howells 9381da177e4SLinus Torvalds ret = 0; 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds error: 9411da177e4SLinus Torvalds return ret; 94276d8aeabSDavid Howells nomem: 94376d8aeabSDavid Howells ret = -ENOMEM; 94476d8aeabSDavid Howells up_write(&keyring->sem); 94576d8aeabSDavid Howells goto error; 946*a8b17ed0SDavid Howells } 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds EXPORT_SYMBOL(key_unlink); 9491da177e4SLinus Torvalds 9501da177e4SLinus Torvalds /* 95176d8aeabSDavid Howells * dispose of a keyring list after the RCU grace period, releasing the keys it 95276d8aeabSDavid Howells * links to 95376d8aeabSDavid Howells */ 95476d8aeabSDavid Howells static void keyring_clear_rcu_disposal(struct rcu_head *rcu) 95576d8aeabSDavid Howells { 95676d8aeabSDavid Howells struct keyring_list *klist; 95776d8aeabSDavid Howells int loop; 95876d8aeabSDavid Howells 95976d8aeabSDavid Howells klist = container_of(rcu, struct keyring_list, rcu); 96076d8aeabSDavid Howells 96176d8aeabSDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 96276d8aeabSDavid Howells key_put(klist->keys[loop]); 96376d8aeabSDavid Howells 96476d8aeabSDavid Howells kfree(klist); 965*a8b17ed0SDavid Howells } 96676d8aeabSDavid Howells 96776d8aeabSDavid Howells /* 9681da177e4SLinus Torvalds * clear the specified process keyring 9691da177e4SLinus Torvalds * - implements keyctl(KEYCTL_CLEAR) 9701da177e4SLinus Torvalds */ 9711da177e4SLinus Torvalds int keyring_clear(struct key *keyring) 9721da177e4SLinus Torvalds { 9731da177e4SLinus Torvalds struct keyring_list *klist; 97476d8aeabSDavid Howells int ret; 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds ret = -ENOTDIR; 9771da177e4SLinus Torvalds if (keyring->type == &key_type_keyring) { 9781da177e4SLinus Torvalds /* detach the pointer block with the locks held */ 9791da177e4SLinus Torvalds down_write(&keyring->sem); 9801da177e4SLinus Torvalds 981f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 9821da177e4SLinus Torvalds if (klist) { 9831da177e4SLinus Torvalds /* adjust the quota */ 9841da177e4SLinus Torvalds key_payload_reserve(keyring, 9851da177e4SLinus Torvalds sizeof(struct keyring_list)); 9861da177e4SLinus Torvalds 98776d8aeabSDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, 98876d8aeabSDavid Howells NULL); 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds up_write(&keyring->sem); 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds /* free the keys after the locks have been dropped */ 99476d8aeabSDavid Howells if (klist) 99576d8aeabSDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 9961da177e4SLinus Torvalds 9971da177e4SLinus Torvalds ret = 0; 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds return ret; 1001*a8b17ed0SDavid Howells } 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds EXPORT_SYMBOL(keyring_clear); 100431204ed9SDavid Howells 100531204ed9SDavid Howells /* 100631204ed9SDavid Howells * dispose of the links from a revoked keyring 100731204ed9SDavid Howells * - called with the key sem write-locked 100831204ed9SDavid Howells */ 100931204ed9SDavid Howells static void keyring_revoke(struct key *keyring) 101031204ed9SDavid Howells { 1011f0641cbaSDavid Howells struct keyring_list *klist; 1012f0641cbaSDavid Howells 1013f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 101431204ed9SDavid Howells 101531204ed9SDavid Howells /* adjust the quota */ 101631204ed9SDavid Howells key_payload_reserve(keyring, 0); 101731204ed9SDavid Howells 101831204ed9SDavid Howells if (klist) { 101931204ed9SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, NULL); 102031204ed9SDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 102131204ed9SDavid Howells } 1022*a8b17ed0SDavid Howells } 10235d135440SDavid Howells 10245d135440SDavid Howells /* 10255d135440SDavid Howells * Determine whether a key is dead 10265d135440SDavid Howells */ 10275d135440SDavid Howells static bool key_is_dead(struct key *key, time_t limit) 10285d135440SDavid Howells { 10295d135440SDavid Howells return test_bit(KEY_FLAG_DEAD, &key->flags) || 10305d135440SDavid Howells (key->expiry > 0 && key->expiry <= limit); 10315d135440SDavid Howells } 10325d135440SDavid Howells 10335d135440SDavid Howells /* 10345d135440SDavid Howells * Collect garbage from the contents of a keyring 10355d135440SDavid Howells */ 10365d135440SDavid Howells void keyring_gc(struct key *keyring, time_t limit) 10375d135440SDavid Howells { 10385d135440SDavid Howells struct keyring_list *klist, *new; 10395d135440SDavid Howells struct key *key; 10405d135440SDavid Howells int loop, keep, max; 10415d135440SDavid Howells 1042c08ef808SDavid Howells kenter("{%x,%s}", key_serial(keyring), keyring->description); 10435d135440SDavid Howells 10445d135440SDavid Howells down_write(&keyring->sem); 10455d135440SDavid Howells 1046f0641cbaSDavid Howells klist = rcu_dereference_locked_keyring(keyring); 10475d135440SDavid Howells if (!klist) 1048c08ef808SDavid Howells goto no_klist; 10495d135440SDavid Howells 10505d135440SDavid Howells /* work out how many subscriptions we're keeping */ 10515d135440SDavid Howells keep = 0; 10525d135440SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) 1053c08ef808SDavid Howells if (!key_is_dead(klist->keys[loop], limit)) 10545d135440SDavid Howells keep++; 10555d135440SDavid Howells 10565d135440SDavid Howells if (keep == klist->nkeys) 10575d135440SDavid Howells goto just_return; 10585d135440SDavid Howells 10595d135440SDavid Howells /* allocate a new keyring payload */ 10605d135440SDavid Howells max = roundup(keep, 4); 10615d135440SDavid Howells new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), 10625d135440SDavid Howells GFP_KERNEL); 10635d135440SDavid Howells if (!new) 1064c08ef808SDavid Howells goto nomem; 10655d135440SDavid Howells new->maxkeys = max; 10665d135440SDavid Howells new->nkeys = 0; 10675d135440SDavid Howells new->delkey = 0; 10685d135440SDavid Howells 10695d135440SDavid Howells /* install the live keys 10705d135440SDavid Howells * - must take care as expired keys may be updated back to life 10715d135440SDavid Howells */ 10725d135440SDavid Howells keep = 0; 10735d135440SDavid Howells for (loop = klist->nkeys - 1; loop >= 0; loop--) { 10745d135440SDavid Howells key = klist->keys[loop]; 10755d135440SDavid Howells if (!key_is_dead(key, limit)) { 10765d135440SDavid Howells if (keep >= max) 10775d135440SDavid Howells goto discard_new; 10785d135440SDavid Howells new->keys[keep++] = key_get(key); 10795d135440SDavid Howells } 10805d135440SDavid Howells } 10815d135440SDavid Howells new->nkeys = keep; 10825d135440SDavid Howells 10835d135440SDavid Howells /* adjust the quota */ 10845d135440SDavid Howells key_payload_reserve(keyring, 10855d135440SDavid Howells sizeof(struct keyring_list) + 10865d135440SDavid Howells KEYQUOTA_LINK_BYTES * keep); 10875d135440SDavid Howells 10885d135440SDavid Howells if (keep == 0) { 10895d135440SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, NULL); 10905d135440SDavid Howells kfree(new); 10915d135440SDavid Howells } else { 10925d135440SDavid Howells rcu_assign_pointer(keyring->payload.subscriptions, new); 10935d135440SDavid Howells } 10945d135440SDavid Howells 10955d135440SDavid Howells up_write(&keyring->sem); 10965d135440SDavid Howells 10975d135440SDavid Howells call_rcu(&klist->rcu, keyring_clear_rcu_disposal); 10985d135440SDavid Howells kleave(" [yes]"); 10995d135440SDavid Howells return; 11005d135440SDavid Howells 11015d135440SDavid Howells discard_new: 11025d135440SDavid Howells new->nkeys = keep; 11035d135440SDavid Howells keyring_clear_rcu_disposal(&new->rcu); 1104c08ef808SDavid Howells up_write(&keyring->sem); 1105c08ef808SDavid Howells kleave(" [discard]"); 1106c08ef808SDavid Howells return; 1107c08ef808SDavid Howells 11085d135440SDavid Howells just_return: 11095d135440SDavid Howells up_write(&keyring->sem); 1110c08ef808SDavid Howells kleave(" [no dead]"); 1111c08ef808SDavid Howells return; 1112c08ef808SDavid Howells 1113c08ef808SDavid Howells no_klist: 1114c08ef808SDavid Howells up_write(&keyring->sem); 1115c08ef808SDavid Howells kleave(" [no_klist]"); 1116c08ef808SDavid Howells return; 1117c08ef808SDavid Howells 1118c08ef808SDavid Howells nomem: 1119c08ef808SDavid Howells up_write(&keyring->sem); 1120c08ef808SDavid Howells kleave(" [oom]"); 11215d135440SDavid Howells } 1122