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 91ad73a717SSerge E. Hallyn static struct rb_node *key_serial_next(struct rb_node *n) 92454804abSSerge E. Hallyn { 93ad73a717SSerge E. Hallyn struct user_namespace *user_ns = current_user_ns(); 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); 98ad73a717SSerge E. Hallyn if (key->user->user_ns == user_ns) 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 110ad73a717SSerge E. Hallyn static struct key *find_ge_key(key_serial_t id) 111ad73a717SSerge E. Hallyn { 112ad73a717SSerge E. Hallyn struct user_namespace *user_ns = current_user_ns(); 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 (;;) { 135ad73a717SSerge E. Hallyn if (minkey->user->user_ns == user_ns) 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; 154ad73a717SSerge E. Hallyn key = find_ge_key(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 171ad73a717SSerge E. Hallyn n = key_serial_next(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 { 185927942aaSDavid Howells const struct cred *cred = current_cred(); 1861da177e4SLinus Torvalds struct rb_node *_p = v; 1871da177e4SLinus Torvalds struct key *key = rb_entry(_p, struct key, serial_node); 1881da177e4SLinus Torvalds struct timespec now; 1891da177e4SLinus Torvalds unsigned long timo; 190927942aaSDavid Howells key_ref_t key_ref, skey_ref; 1911da177e4SLinus Torvalds char xbuf[12]; 19206ec7be5SMichael LeMay int rc; 19306ec7be5SMichael LeMay 194927942aaSDavid Howells key_ref = make_key_ref(key, 0); 195927942aaSDavid Howells 196927942aaSDavid Howells /* determine if the key is possessed by this process (a test we can 197927942aaSDavid Howells * skip if the key does not indicate the possessor can view it 198927942aaSDavid Howells */ 199927942aaSDavid Howells if (key->perm & KEY_POS_VIEW) { 200927942aaSDavid Howells skey_ref = search_my_process_keyrings(key->type, key, 201927942aaSDavid Howells lookup_user_key_possessed, 20278b7280cSDavid Howells true, cred); 203927942aaSDavid Howells if (!IS_ERR(skey_ref)) { 204927942aaSDavid Howells key_ref_put(skey_ref); 205927942aaSDavid Howells key_ref = make_key_ref(key, 1); 206927942aaSDavid Howells } 207927942aaSDavid Howells } 208927942aaSDavid Howells 20906ec7be5SMichael LeMay /* check whether the current task is allowed to view the key (assuming 210d84f4f99SDavid Howells * non-possession) 211d84f4f99SDavid Howells * - the caller holds a spinlock, and thus the RCU read lock, making our 212d84f4f99SDavid Howells * access to __current_cred() safe 213d84f4f99SDavid Howells */ 214927942aaSDavid Howells rc = key_task_permission(key_ref, cred, KEY_VIEW); 21506ec7be5SMichael LeMay if (rc < 0) 21606ec7be5SMichael LeMay return 0; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds now = current_kernel_time(); 2191da177e4SLinus Torvalds 22076d8aeabSDavid Howells rcu_read_lock(); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* come up with a suitable timeout value */ 2231da177e4SLinus Torvalds if (key->expiry == 0) { 2241da177e4SLinus Torvalds memcpy(xbuf, "perm", 5); 2257b1b9164SDavid Howells } else if (now.tv_sec >= key->expiry) { 2261da177e4SLinus Torvalds memcpy(xbuf, "expd", 5); 2277b1b9164SDavid Howells } else { 2281da177e4SLinus Torvalds timo = key->expiry - now.tv_sec; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds if (timo < 60) 2311da177e4SLinus Torvalds sprintf(xbuf, "%lus", timo); 2321da177e4SLinus Torvalds else if (timo < 60*60) 2331da177e4SLinus Torvalds sprintf(xbuf, "%lum", timo / 60); 2341da177e4SLinus Torvalds else if (timo < 60*60*24) 2351da177e4SLinus Torvalds sprintf(xbuf, "%luh", timo / (60*60)); 2361da177e4SLinus Torvalds else if (timo < 60*60*24*7) 2371da177e4SLinus Torvalds sprintf(xbuf, "%lud", timo / (60*60*24)); 2381da177e4SLinus Torvalds else 2391da177e4SLinus Torvalds sprintf(xbuf, "%luw", timo / (60*60*24*7)); 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds 24276d8aeabSDavid Howells #define showflag(KEY, LETTER, FLAG) \ 24376d8aeabSDavid Howells (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') 24476d8aeabSDavid Howells 245*fd75815fSDavid Howells seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 2461da177e4SLinus Torvalds key->serial, 24776d8aeabSDavid Howells showflag(key, 'I', KEY_FLAG_INSTANTIATED), 24876d8aeabSDavid Howells showflag(key, 'R', KEY_FLAG_REVOKED), 24976d8aeabSDavid Howells showflag(key, 'D', KEY_FLAG_DEAD), 25076d8aeabSDavid Howells showflag(key, 'Q', KEY_FLAG_IN_QUOTA), 25176d8aeabSDavid Howells showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), 25276d8aeabSDavid Howells showflag(key, 'N', KEY_FLAG_NEGATIVE), 253*fd75815fSDavid Howells showflag(key, 'i', KEY_FLAG_INVALIDATED), 2541da177e4SLinus Torvalds atomic_read(&key->usage), 2551da177e4SLinus Torvalds xbuf, 2561da177e4SLinus Torvalds key->perm, 2571da177e4SLinus Torvalds key->uid, 2581da177e4SLinus Torvalds key->gid, 2591da177e4SLinus Torvalds key->type->name); 2601da177e4SLinus Torvalds 26176d8aeabSDavid Howells #undef showflag 26276d8aeabSDavid Howells 2631da177e4SLinus Torvalds if (key->type->describe) 2641da177e4SLinus Torvalds key->type->describe(key, m); 2651da177e4SLinus Torvalds seq_putc(m, '\n'); 2661da177e4SLinus Torvalds 26776d8aeabSDavid Howells rcu_read_unlock(); 2681da177e4SLinus Torvalds return 0; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ 2721da177e4SLinus Torvalds 273454804abSSerge E. Hallyn static struct rb_node *__key_user_next(struct rb_node *n) 274454804abSSerge E. Hallyn { 275454804abSSerge E. Hallyn while (n) { 276454804abSSerge E. Hallyn struct key_user *user = rb_entry(n, struct key_user, node); 277454804abSSerge E. Hallyn if (user->user_ns == current_user_ns()) 278454804abSSerge E. Hallyn break; 279454804abSSerge E. Hallyn n = rb_next(n); 280454804abSSerge E. Hallyn } 281454804abSSerge E. Hallyn return n; 282454804abSSerge E. Hallyn } 283454804abSSerge E. Hallyn 284454804abSSerge E. Hallyn static struct rb_node *key_user_next(struct rb_node *n) 285454804abSSerge E. Hallyn { 286454804abSSerge E. Hallyn return __key_user_next(rb_next(n)); 287454804abSSerge E. Hallyn } 288454804abSSerge E. Hallyn 289454804abSSerge E. Hallyn static struct rb_node *key_user_first(struct rb_root *r) 290454804abSSerge E. Hallyn { 291454804abSSerge E. Hallyn struct rb_node *n = rb_first(r); 292454804abSSerge E. Hallyn return __key_user_next(n); 293454804abSSerge E. Hallyn } 2947b1b9164SDavid Howells 2951da177e4SLinus Torvalds /* 296973c9f4fSDavid Howells * Implement "/proc/key-users" to provides a list of the key users and their 297973c9f4fSDavid Howells * quotas. 2981da177e4SLinus Torvalds */ 2991da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file) 3001da177e4SLinus Torvalds { 3011da177e4SLinus Torvalds return seq_open(file, &proc_key_users_ops); 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) 30586abcf9cSJames Morris __acquires(key_user_lock) 3061da177e4SLinus Torvalds { 3071da177e4SLinus Torvalds struct rb_node *_p; 3081da177e4SLinus Torvalds loff_t pos = *_pos; 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds spin_lock(&key_user_lock); 3111da177e4SLinus Torvalds 312454804abSSerge E. Hallyn _p = key_user_first(&key_user_tree); 3131da177e4SLinus Torvalds while (pos > 0 && _p) { 3141da177e4SLinus Torvalds pos--; 315454804abSSerge E. Hallyn _p = key_user_next(_p); 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds return _p; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds (*_pos)++; 324454804abSSerge E. Hallyn return key_user_next((struct rb_node *)v); 3251da177e4SLinus Torvalds } 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v) 32886abcf9cSJames Morris __releases(key_user_lock) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds spin_unlock(&key_user_lock); 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds 3331da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v) 3341da177e4SLinus Torvalds { 3351da177e4SLinus Torvalds struct rb_node *_p = v; 3361da177e4SLinus Torvalds struct key_user *user = rb_entry(_p, struct key_user, node); 3370b77f5bfSDavid Howells unsigned maxkeys = (user->uid == 0) ? 3380b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 3390b77f5bfSDavid Howells unsigned maxbytes = (user->uid == 0) ? 3400b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", 3431da177e4SLinus Torvalds user->uid, 3441da177e4SLinus Torvalds atomic_read(&user->usage), 3451da177e4SLinus Torvalds atomic_read(&user->nkeys), 3461da177e4SLinus Torvalds atomic_read(&user->nikeys), 3471da177e4SLinus Torvalds user->qnkeys, 3480b77f5bfSDavid Howells maxkeys, 3491da177e4SLinus Torvalds user->qnbytes, 3500b77f5bfSDavid Howells maxbytes); 3511da177e4SLinus Torvalds 3521da177e4SLinus Torvalds return 0; 3531da177e4SLinus Torvalds } 354