1973c9f4fSDavid Howells /* procfs files for key database enumeration 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright (C) 2004 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/fs.h> 161da177e4SLinus Torvalds #include <linux/proc_fs.h> 171da177e4SLinus Torvalds #include <linux/seq_file.h> 181da177e4SLinus Torvalds #include <asm/errno.h> 191da177e4SLinus Torvalds #include "internal.h" 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 221da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file); 231da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos); 241da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); 251da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v); 261da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v); 271da177e4SLinus Torvalds 281996a109SJan Engelhardt static const struct seq_operations proc_keys_ops = { 291da177e4SLinus Torvalds .start = proc_keys_start, 301da177e4SLinus Torvalds .next = proc_keys_next, 311da177e4SLinus Torvalds .stop = proc_keys_stop, 321da177e4SLinus Torvalds .show = proc_keys_show, 331da177e4SLinus Torvalds }; 341da177e4SLinus Torvalds 359c2e08c5SArjan van de Ven static const struct file_operations proc_keys_fops = { 361da177e4SLinus Torvalds .open = proc_keys_open, 371da177e4SLinus Torvalds .read = seq_read, 381da177e4SLinus Torvalds .llseek = seq_lseek, 391da177e4SLinus Torvalds .release = seq_release, 401da177e4SLinus Torvalds }; 411da177e4SLinus Torvalds #endif 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file); 441da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); 451da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos); 461da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v); 471da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v); 481da177e4SLinus Torvalds 491996a109SJan Engelhardt static const struct seq_operations proc_key_users_ops = { 501da177e4SLinus Torvalds .start = proc_key_users_start, 511da177e4SLinus Torvalds .next = proc_key_users_next, 521da177e4SLinus Torvalds .stop = proc_key_users_stop, 531da177e4SLinus Torvalds .show = proc_key_users_show, 541da177e4SLinus Torvalds }; 551da177e4SLinus Torvalds 569c2e08c5SArjan van de Ven static const struct file_operations proc_key_users_fops = { 571da177e4SLinus Torvalds .open = proc_key_users_open, 581da177e4SLinus Torvalds .read = seq_read, 591da177e4SLinus Torvalds .llseek = seq_lseek, 601da177e4SLinus Torvalds .release = seq_release, 611da177e4SLinus Torvalds }; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 64973c9f4fSDavid Howells * Declare the /proc files. 651da177e4SLinus Torvalds */ 661da177e4SLinus Torvalds static int __init key_proc_init(void) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds struct proc_dir_entry *p; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 71da91d2efSAlexey Dobriyan p = proc_create("keys", 0, NULL, &proc_keys_fops); 721da177e4SLinus Torvalds if (!p) 731da177e4SLinus Torvalds panic("Cannot create /proc/keys\n"); 741da177e4SLinus Torvalds #endif 751da177e4SLinus Torvalds 76da91d2efSAlexey Dobriyan p = proc_create("key-users", 0, NULL, &proc_key_users_fops); 771da177e4SLinus Torvalds if (!p) 781da177e4SLinus Torvalds panic("Cannot create /proc/key-users\n"); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds return 0; 81a8b17ed0SDavid Howells } 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds __initcall(key_proc_init); 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* 86973c9f4fSDavid Howells * Implement "/proc/keys" to provide a list of the keys on the system that 87973c9f4fSDavid Howells * grant View permission to the caller. 881da177e4SLinus Torvalds */ 891da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 901da177e4SLinus Torvalds 919a56c2dbSEric W. Biederman static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n) 92454804abSSerge E. Hallyn { 939a56c2dbSEric W. Biederman struct user_namespace *user_ns = seq_user_ns(p); 94ad73a717SSerge E. Hallyn 95ad73a717SSerge E. Hallyn n = rb_next(n); 96454804abSSerge E. Hallyn while (n) { 97454804abSSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 989a56c2dbSEric W. Biederman if (kuid_has_mapping(user_ns, key->user->uid)) 99454804abSSerge E. Hallyn break; 100454804abSSerge E. Hallyn n = rb_next(n); 101454804abSSerge E. Hallyn } 102454804abSSerge E. Hallyn return n; 103454804abSSerge E. Hallyn } 104454804abSSerge E. Hallyn 1051da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds return seq_open(file, &proc_keys_ops); 108ad73a717SSerge E. Hallyn } 1091da177e4SLinus Torvalds 1109a56c2dbSEric W. Biederman static struct key *find_ge_key(struct seq_file *p, key_serial_t id) 111ad73a717SSerge E. Hallyn { 1129a56c2dbSEric W. Biederman struct user_namespace *user_ns = seq_user_ns(p); 113ad73a717SSerge E. Hallyn struct rb_node *n = key_serial_tree.rb_node; 114ad73a717SSerge E. Hallyn struct key *minkey = NULL; 115ad73a717SSerge E. Hallyn 116ad73a717SSerge E. Hallyn while (n) { 117ad73a717SSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 118ad73a717SSerge E. Hallyn if (id < key->serial) { 119ad73a717SSerge E. Hallyn if (!minkey || minkey->serial > key->serial) 120ad73a717SSerge E. Hallyn minkey = key; 121ad73a717SSerge E. Hallyn n = n->rb_left; 122ad73a717SSerge E. Hallyn } else if (id > key->serial) { 123ad73a717SSerge E. Hallyn n = n->rb_right; 124ad73a717SSerge E. Hallyn } else { 125ad73a717SSerge E. Hallyn minkey = key; 126ad73a717SSerge E. Hallyn break; 127ad73a717SSerge E. Hallyn } 128ad73a717SSerge E. Hallyn key = NULL; 129ad73a717SSerge E. Hallyn } 130ad73a717SSerge E. Hallyn 131ad73a717SSerge E. Hallyn if (!minkey) 132ad73a717SSerge E. Hallyn return NULL; 133ad73a717SSerge E. Hallyn 134ad73a717SSerge E. Hallyn for (;;) { 1359a56c2dbSEric W. Biederman if (kuid_has_mapping(user_ns, minkey->user->uid)) 136ad73a717SSerge E. Hallyn return minkey; 137ad73a717SSerge E. Hallyn n = rb_next(&minkey->serial_node); 138ad73a717SSerge E. Hallyn if (!n) 139ad73a717SSerge E. Hallyn return NULL; 140ad73a717SSerge E. Hallyn minkey = rb_entry(n, struct key, serial_node); 141ad73a717SSerge E. Hallyn } 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos) 14586abcf9cSJames Morris __acquires(key_serial_lock) 1461da177e4SLinus Torvalds { 147ad73a717SSerge E. Hallyn key_serial_t pos = *_pos; 148ad73a717SSerge E. Hallyn struct key *key; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds spin_lock(&key_serial_lock); 1511da177e4SLinus Torvalds 152ad73a717SSerge E. Hallyn if (*_pos > INT_MAX) 153ad73a717SSerge E. Hallyn return NULL; 1549a56c2dbSEric W. Biederman key = find_ge_key(p, pos); 155ad73a717SSerge E. Hallyn if (!key) 156ad73a717SSerge E. Hallyn return NULL; 157ad73a717SSerge E. Hallyn *_pos = key->serial; 158ad73a717SSerge E. Hallyn return &key->serial_node; 1591da177e4SLinus Torvalds } 1601da177e4SLinus Torvalds 161ad73a717SSerge E. Hallyn static inline key_serial_t key_node_serial(struct rb_node *n) 162ad73a717SSerge E. Hallyn { 163ad73a717SSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 164ad73a717SSerge E. Hallyn return key->serial; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) 1681da177e4SLinus Torvalds { 169ad73a717SSerge E. Hallyn struct rb_node *n; 1701da177e4SLinus Torvalds 1719a56c2dbSEric W. Biederman n = key_serial_next(p, v); 172ad73a717SSerge E. Hallyn if (n) 173ad73a717SSerge E. Hallyn *_pos = key_node_serial(n); 174ad73a717SSerge E. Hallyn return n; 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v) 17886abcf9cSJames Morris __releases(key_serial_lock) 1791da177e4SLinus Torvalds { 1801da177e4SLinus Torvalds spin_unlock(&key_serial_lock); 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v) 1841da177e4SLinus Torvalds { 1851da177e4SLinus Torvalds struct rb_node *_p = v; 1861da177e4SLinus Torvalds struct key *key = rb_entry(_p, struct key, serial_node); 1871da177e4SLinus Torvalds struct timespec now; 1881da177e4SLinus Torvalds unsigned long timo; 189927942aaSDavid Howells key_ref_t key_ref, skey_ref; 1901da177e4SLinus Torvalds char xbuf[12]; 19106ec7be5SMichael LeMay int rc; 19206ec7be5SMichael LeMay 1934bdf0bc3SDavid Howells struct keyring_search_context ctx = { 1944bdf0bc3SDavid Howells .index_key.type = key->type, 1954bdf0bc3SDavid Howells .index_key.description = key->description, 1964bdf0bc3SDavid Howells .cred = current_cred(), 1974bdf0bc3SDavid Howells .match = lookup_user_key_possessed, 1984bdf0bc3SDavid Howells .match_data = key, 1994bdf0bc3SDavid Howells .flags = (KEYRING_SEARCH_NO_STATE_CHECK | 2004bdf0bc3SDavid Howells KEYRING_SEARCH_LOOKUP_DIRECT), 2014bdf0bc3SDavid Howells }; 2024bdf0bc3SDavid Howells 203927942aaSDavid Howells key_ref = make_key_ref(key, 0); 204927942aaSDavid Howells 205927942aaSDavid Howells /* determine if the key is possessed by this process (a test we can 206927942aaSDavid Howells * skip if the key does not indicate the possessor can view it 207927942aaSDavid Howells */ 208927942aaSDavid Howells if (key->perm & KEY_POS_VIEW) { 2094bdf0bc3SDavid Howells skey_ref = search_my_process_keyrings(&ctx); 210927942aaSDavid Howells if (!IS_ERR(skey_ref)) { 211927942aaSDavid Howells key_ref_put(skey_ref); 212927942aaSDavid Howells key_ref = make_key_ref(key, 1); 213927942aaSDavid Howells } 214927942aaSDavid Howells } 215927942aaSDavid Howells 21606ec7be5SMichael LeMay /* check whether the current task is allowed to view the key (assuming 217d84f4f99SDavid Howells * non-possession) 218d84f4f99SDavid Howells * - the caller holds a spinlock, and thus the RCU read lock, making our 219d84f4f99SDavid Howells * access to __current_cred() safe 220d84f4f99SDavid Howells */ 221*f5895943SDavid Howells rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); 22206ec7be5SMichael LeMay if (rc < 0) 22306ec7be5SMichael LeMay return 0; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds now = current_kernel_time(); 2261da177e4SLinus Torvalds 22776d8aeabSDavid Howells rcu_read_lock(); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* come up with a suitable timeout value */ 2301da177e4SLinus Torvalds if (key->expiry == 0) { 2311da177e4SLinus Torvalds memcpy(xbuf, "perm", 5); 2327b1b9164SDavid Howells } else if (now.tv_sec >= key->expiry) { 2331da177e4SLinus Torvalds memcpy(xbuf, "expd", 5); 2347b1b9164SDavid Howells } else { 2351da177e4SLinus Torvalds timo = key->expiry - now.tv_sec; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds if (timo < 60) 2381da177e4SLinus Torvalds sprintf(xbuf, "%lus", timo); 2391da177e4SLinus Torvalds else if (timo < 60*60) 2401da177e4SLinus Torvalds sprintf(xbuf, "%lum", timo / 60); 2411da177e4SLinus Torvalds else if (timo < 60*60*24) 2421da177e4SLinus Torvalds sprintf(xbuf, "%luh", timo / (60*60)); 2431da177e4SLinus Torvalds else if (timo < 60*60*24*7) 2441da177e4SLinus Torvalds sprintf(xbuf, "%lud", timo / (60*60*24)); 2451da177e4SLinus Torvalds else 2461da177e4SLinus Torvalds sprintf(xbuf, "%luw", timo / (60*60*24*7)); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 24976d8aeabSDavid Howells #define showflag(KEY, LETTER, FLAG) \ 25076d8aeabSDavid Howells (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') 25176d8aeabSDavid Howells 252fd75815fSDavid Howells seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 2531da177e4SLinus Torvalds key->serial, 25476d8aeabSDavid Howells showflag(key, 'I', KEY_FLAG_INSTANTIATED), 25576d8aeabSDavid Howells showflag(key, 'R', KEY_FLAG_REVOKED), 25676d8aeabSDavid Howells showflag(key, 'D', KEY_FLAG_DEAD), 25776d8aeabSDavid Howells showflag(key, 'Q', KEY_FLAG_IN_QUOTA), 25876d8aeabSDavid Howells showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), 25976d8aeabSDavid Howells showflag(key, 'N', KEY_FLAG_NEGATIVE), 260fd75815fSDavid Howells showflag(key, 'i', KEY_FLAG_INVALIDATED), 2611da177e4SLinus Torvalds atomic_read(&key->usage), 2621da177e4SLinus Torvalds xbuf, 2631da177e4SLinus Torvalds key->perm, 2649a56c2dbSEric W. Biederman from_kuid_munged(seq_user_ns(m), key->uid), 2659a56c2dbSEric W. Biederman from_kgid_munged(seq_user_ns(m), key->gid), 2661da177e4SLinus Torvalds key->type->name); 2671da177e4SLinus Torvalds 26876d8aeabSDavid Howells #undef showflag 26976d8aeabSDavid Howells 2701da177e4SLinus Torvalds if (key->type->describe) 2711da177e4SLinus Torvalds key->type->describe(key, m); 2721da177e4SLinus Torvalds seq_putc(m, '\n'); 2731da177e4SLinus Torvalds 27476d8aeabSDavid Howells rcu_read_unlock(); 2751da177e4SLinus Torvalds return 0; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ 2791da177e4SLinus Torvalds 2809a56c2dbSEric W. Biederman static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n) 281454804abSSerge E. Hallyn { 282454804abSSerge E. Hallyn while (n) { 283454804abSSerge E. Hallyn struct key_user *user = rb_entry(n, struct key_user, node); 2849a56c2dbSEric W. Biederman if (kuid_has_mapping(user_ns, user->uid)) 285454804abSSerge E. Hallyn break; 286454804abSSerge E. Hallyn n = rb_next(n); 287454804abSSerge E. Hallyn } 288454804abSSerge E. Hallyn return n; 289454804abSSerge E. Hallyn } 290454804abSSerge E. Hallyn 2919a56c2dbSEric W. Biederman static struct rb_node *key_user_next(struct user_namespace *user_ns, struct rb_node *n) 292454804abSSerge E. Hallyn { 2939a56c2dbSEric W. Biederman return __key_user_next(user_ns, rb_next(n)); 294454804abSSerge E. Hallyn } 295454804abSSerge E. Hallyn 2969a56c2dbSEric W. Biederman static struct rb_node *key_user_first(struct user_namespace *user_ns, struct rb_root *r) 297454804abSSerge E. Hallyn { 298454804abSSerge E. Hallyn struct rb_node *n = rb_first(r); 2999a56c2dbSEric W. Biederman return __key_user_next(user_ns, n); 300454804abSSerge E. Hallyn } 3017b1b9164SDavid Howells 3021da177e4SLinus Torvalds /* 303973c9f4fSDavid Howells * Implement "/proc/key-users" to provides a list of the key users and their 304973c9f4fSDavid Howells * quotas. 3051da177e4SLinus Torvalds */ 3061da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds return seq_open(file, &proc_key_users_ops); 3091da177e4SLinus Torvalds } 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) 31286abcf9cSJames Morris __acquires(key_user_lock) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds struct rb_node *_p; 3151da177e4SLinus Torvalds loff_t pos = *_pos; 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds spin_lock(&key_user_lock); 3181da177e4SLinus Torvalds 3199a56c2dbSEric W. Biederman _p = key_user_first(seq_user_ns(p), &key_user_tree); 3201da177e4SLinus Torvalds while (pos > 0 && _p) { 3211da177e4SLinus Torvalds pos--; 3229a56c2dbSEric W. Biederman _p = key_user_next(seq_user_ns(p), _p); 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds return _p; 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds (*_pos)++; 3319a56c2dbSEric W. Biederman return key_user_next(seq_user_ns(p), (struct rb_node *)v); 3321da177e4SLinus Torvalds } 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v) 33586abcf9cSJames Morris __releases(key_user_lock) 3361da177e4SLinus Torvalds { 3371da177e4SLinus Torvalds spin_unlock(&key_user_lock); 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v) 3411da177e4SLinus Torvalds { 3421da177e4SLinus Torvalds struct rb_node *_p = v; 3431da177e4SLinus Torvalds struct key_user *user = rb_entry(_p, struct key_user, node); 3449a56c2dbSEric W. Biederman unsigned maxkeys = uid_eq(user->uid, GLOBAL_ROOT_UID) ? 3450b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 3469a56c2dbSEric W. Biederman unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ? 3470b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", 3509a56c2dbSEric W. Biederman from_kuid_munged(seq_user_ns(m), user->uid), 3511da177e4SLinus Torvalds atomic_read(&user->usage), 3521da177e4SLinus Torvalds atomic_read(&user->nkeys), 3531da177e4SLinus Torvalds atomic_read(&user->nikeys), 3541da177e4SLinus Torvalds user->qnkeys, 3550b77f5bfSDavid Howells maxkeys, 3561da177e4SLinus Torvalds user->qnbytes, 3570b77f5bfSDavid Howells maxbytes); 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds return 0; 3601da177e4SLinus Torvalds } 361