11da177e4SLinus Torvalds /* proc.c: proc 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/slab.h> 161da177e4SLinus Torvalds #include <linux/fs.h> 171da177e4SLinus Torvalds #include <linux/proc_fs.h> 181da177e4SLinus Torvalds #include <linux/seq_file.h> 191da177e4SLinus Torvalds #include <asm/errno.h> 201da177e4SLinus Torvalds #include "internal.h" 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 231da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file); 241da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos); 251da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos); 261da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v); 271da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v); 281da177e4SLinus Torvalds 291996a109SJan Engelhardt static const struct seq_operations proc_keys_ops = { 301da177e4SLinus Torvalds .start = proc_keys_start, 311da177e4SLinus Torvalds .next = proc_keys_next, 321da177e4SLinus Torvalds .stop = proc_keys_stop, 331da177e4SLinus Torvalds .show = proc_keys_show, 341da177e4SLinus Torvalds }; 351da177e4SLinus Torvalds 369c2e08c5SArjan van de Ven static const struct file_operations proc_keys_fops = { 371da177e4SLinus Torvalds .open = proc_keys_open, 381da177e4SLinus Torvalds .read = seq_read, 391da177e4SLinus Torvalds .llseek = seq_lseek, 401da177e4SLinus Torvalds .release = seq_release, 411da177e4SLinus Torvalds }; 421da177e4SLinus Torvalds #endif 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file); 451da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos); 461da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos); 471da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v); 481da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v); 491da177e4SLinus Torvalds 501996a109SJan Engelhardt static const struct seq_operations proc_key_users_ops = { 511da177e4SLinus Torvalds .start = proc_key_users_start, 521da177e4SLinus Torvalds .next = proc_key_users_next, 531da177e4SLinus Torvalds .stop = proc_key_users_stop, 541da177e4SLinus Torvalds .show = proc_key_users_show, 551da177e4SLinus Torvalds }; 561da177e4SLinus Torvalds 579c2e08c5SArjan van de Ven static const struct file_operations proc_key_users_fops = { 581da177e4SLinus Torvalds .open = proc_key_users_open, 591da177e4SLinus Torvalds .read = seq_read, 601da177e4SLinus Torvalds .llseek = seq_lseek, 611da177e4SLinus Torvalds .release = seq_release, 621da177e4SLinus Torvalds }; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /*****************************************************************************/ 651da177e4SLinus Torvalds /* 661da177e4SLinus Torvalds * declare the /proc files 671da177e4SLinus Torvalds */ 681da177e4SLinus Torvalds static int __init key_proc_init(void) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds struct proc_dir_entry *p; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 73da91d2efSAlexey Dobriyan p = proc_create("keys", 0, NULL, &proc_keys_fops); 741da177e4SLinus Torvalds if (!p) 751da177e4SLinus Torvalds panic("Cannot create /proc/keys\n"); 761da177e4SLinus Torvalds #endif 771da177e4SLinus Torvalds 78da91d2efSAlexey Dobriyan p = proc_create("key-users", 0, NULL, &proc_key_users_fops); 791da177e4SLinus Torvalds if (!p) 801da177e4SLinus Torvalds panic("Cannot create /proc/key-users\n"); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds return 0; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds } /* end key_proc_init() */ 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds __initcall(key_proc_init); 871da177e4SLinus Torvalds 881da177e4SLinus Torvalds /*****************************************************************************/ 891da177e4SLinus Torvalds /* 901da177e4SLinus Torvalds * implement "/proc/keys" to provides a list of the keys on the system 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds #ifdef CONFIG_KEYS_DEBUG_PROC_KEYS 931da177e4SLinus Torvalds 94ad73a717SSerge E. Hallyn static struct rb_node *key_serial_next(struct rb_node *n) 95454804abSSerge E. Hallyn { 96ad73a717SSerge E. Hallyn struct user_namespace *user_ns = current_user_ns(); 97ad73a717SSerge E. Hallyn 98ad73a717SSerge E. Hallyn n = rb_next(n); 99454804abSSerge E. Hallyn while (n) { 100454804abSSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 101ad73a717SSerge E. Hallyn if (key->user->user_ns == user_ns) 102454804abSSerge E. Hallyn break; 103454804abSSerge E. Hallyn n = rb_next(n); 104454804abSSerge E. Hallyn } 105454804abSSerge E. Hallyn return n; 106454804abSSerge E. Hallyn } 107454804abSSerge E. Hallyn 1081da177e4SLinus Torvalds static int proc_keys_open(struct inode *inode, struct file *file) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds return seq_open(file, &proc_keys_ops); 111ad73a717SSerge E. Hallyn } 1121da177e4SLinus Torvalds 113ad73a717SSerge E. Hallyn static struct key *find_ge_key(key_serial_t id) 114ad73a717SSerge E. Hallyn { 115ad73a717SSerge E. Hallyn struct user_namespace *user_ns = current_user_ns(); 116ad73a717SSerge E. Hallyn struct rb_node *n = key_serial_tree.rb_node; 117ad73a717SSerge E. Hallyn struct key *minkey = NULL; 118ad73a717SSerge E. Hallyn 119ad73a717SSerge E. Hallyn while (n) { 120ad73a717SSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 121ad73a717SSerge E. Hallyn if (id < key->serial) { 122ad73a717SSerge E. Hallyn if (!minkey || minkey->serial > key->serial) 123ad73a717SSerge E. Hallyn minkey = key; 124ad73a717SSerge E. Hallyn n = n->rb_left; 125ad73a717SSerge E. Hallyn } else if (id > key->serial) { 126ad73a717SSerge E. Hallyn n = n->rb_right; 127ad73a717SSerge E. Hallyn } else { 128ad73a717SSerge E. Hallyn minkey = key; 129ad73a717SSerge E. Hallyn break; 130ad73a717SSerge E. Hallyn } 131ad73a717SSerge E. Hallyn key = NULL; 132ad73a717SSerge E. Hallyn } 133ad73a717SSerge E. Hallyn 134ad73a717SSerge E. Hallyn if (!minkey) 135ad73a717SSerge E. Hallyn return NULL; 136ad73a717SSerge E. Hallyn 137ad73a717SSerge E. Hallyn for (;;) { 138ad73a717SSerge E. Hallyn if (minkey->user->user_ns == user_ns) 139ad73a717SSerge E. Hallyn return minkey; 140ad73a717SSerge E. Hallyn n = rb_next(&minkey->serial_node); 141ad73a717SSerge E. Hallyn if (!n) 142ad73a717SSerge E. Hallyn return NULL; 143ad73a717SSerge E. Hallyn minkey = rb_entry(n, struct key, serial_node); 144ad73a717SSerge E. Hallyn } 1451da177e4SLinus Torvalds } 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds static void *proc_keys_start(struct seq_file *p, loff_t *_pos) 14886abcf9cSJames Morris __acquires(key_serial_lock) 1491da177e4SLinus Torvalds { 150ad73a717SSerge E. Hallyn key_serial_t pos = *_pos; 151ad73a717SSerge E. Hallyn struct key *key; 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds spin_lock(&key_serial_lock); 1541da177e4SLinus Torvalds 155ad73a717SSerge E. Hallyn if (*_pos > INT_MAX) 156ad73a717SSerge E. Hallyn return NULL; 157ad73a717SSerge E. Hallyn key = find_ge_key(pos); 158ad73a717SSerge E. Hallyn if (!key) 159ad73a717SSerge E. Hallyn return NULL; 160ad73a717SSerge E. Hallyn *_pos = key->serial; 161ad73a717SSerge E. Hallyn return &key->serial_node; 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 164ad73a717SSerge E. Hallyn static inline key_serial_t key_node_serial(struct rb_node *n) 165ad73a717SSerge E. Hallyn { 166ad73a717SSerge E. Hallyn struct key *key = rb_entry(n, struct key, serial_node); 167ad73a717SSerge E. Hallyn return key->serial; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos) 1711da177e4SLinus Torvalds { 172ad73a717SSerge E. Hallyn struct rb_node *n; 1731da177e4SLinus Torvalds 174ad73a717SSerge E. Hallyn n = key_serial_next(v); 175ad73a717SSerge E. Hallyn if (n) 176ad73a717SSerge E. Hallyn *_pos = key_node_serial(n); 177ad73a717SSerge E. Hallyn return n; 1781da177e4SLinus Torvalds } 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds static void proc_keys_stop(struct seq_file *p, void *v) 18186abcf9cSJames Morris __releases(key_serial_lock) 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds spin_unlock(&key_serial_lock); 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds static int proc_keys_show(struct seq_file *m, void *v) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds struct rb_node *_p = v; 1891da177e4SLinus Torvalds struct key *key = rb_entry(_p, struct key, serial_node); 1901da177e4SLinus Torvalds struct timespec now; 1911da177e4SLinus Torvalds unsigned long timo; 1921da177e4SLinus Torvalds char xbuf[12]; 19306ec7be5SMichael LeMay int rc; 19406ec7be5SMichael LeMay 19506ec7be5SMichael LeMay /* check whether the current task is allowed to view the key (assuming 196d84f4f99SDavid Howells * non-possession) 197d84f4f99SDavid Howells * - the caller holds a spinlock, and thus the RCU read lock, making our 198d84f4f99SDavid Howells * access to __current_cred() safe 199d84f4f99SDavid Howells */ 200d84f4f99SDavid Howells rc = key_task_permission(make_key_ref(key, 0), current_cred(), 201d84f4f99SDavid Howells KEY_VIEW); 20206ec7be5SMichael LeMay if (rc < 0) 20306ec7be5SMichael LeMay return 0; 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds now = current_kernel_time(); 2061da177e4SLinus Torvalds 20776d8aeabSDavid Howells rcu_read_lock(); 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* come up with a suitable timeout value */ 2101da177e4SLinus Torvalds if (key->expiry == 0) { 2111da177e4SLinus Torvalds memcpy(xbuf, "perm", 5); 212*7b1b9164SDavid Howells } else if (now.tv_sec >= key->expiry) { 2131da177e4SLinus Torvalds memcpy(xbuf, "expd", 5); 214*7b1b9164SDavid Howells } else { 2151da177e4SLinus Torvalds timo = key->expiry - now.tv_sec; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds if (timo < 60) 2181da177e4SLinus Torvalds sprintf(xbuf, "%lus", timo); 2191da177e4SLinus Torvalds else if (timo < 60*60) 2201da177e4SLinus Torvalds sprintf(xbuf, "%lum", timo / 60); 2211da177e4SLinus Torvalds else if (timo < 60*60*24) 2221da177e4SLinus Torvalds sprintf(xbuf, "%luh", timo / (60*60)); 2231da177e4SLinus Torvalds else if (timo < 60*60*24*7) 2241da177e4SLinus Torvalds sprintf(xbuf, "%lud", timo / (60*60*24)); 2251da177e4SLinus Torvalds else 2261da177e4SLinus Torvalds sprintf(xbuf, "%luw", timo / (60*60*24*7)); 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 22976d8aeabSDavid Howells #define showflag(KEY, LETTER, FLAG) \ 23076d8aeabSDavid Howells (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') 23176d8aeabSDavid Howells 232664cceb0SDavid Howells seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", 2331da177e4SLinus Torvalds key->serial, 23476d8aeabSDavid Howells showflag(key, 'I', KEY_FLAG_INSTANTIATED), 23576d8aeabSDavid Howells showflag(key, 'R', KEY_FLAG_REVOKED), 23676d8aeabSDavid Howells showflag(key, 'D', KEY_FLAG_DEAD), 23776d8aeabSDavid Howells showflag(key, 'Q', KEY_FLAG_IN_QUOTA), 23876d8aeabSDavid Howells showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), 23976d8aeabSDavid Howells showflag(key, 'N', KEY_FLAG_NEGATIVE), 2401da177e4SLinus Torvalds atomic_read(&key->usage), 2411da177e4SLinus Torvalds xbuf, 2421da177e4SLinus Torvalds key->perm, 2431da177e4SLinus Torvalds key->uid, 2441da177e4SLinus Torvalds key->gid, 2451da177e4SLinus Torvalds key->type->name); 2461da177e4SLinus Torvalds 24776d8aeabSDavid Howells #undef showflag 24876d8aeabSDavid Howells 2491da177e4SLinus Torvalds if (key->type->describe) 2501da177e4SLinus Torvalds key->type->describe(key, m); 2511da177e4SLinus Torvalds seq_putc(m, '\n'); 2521da177e4SLinus Torvalds 25376d8aeabSDavid Howells rcu_read_unlock(); 2541da177e4SLinus Torvalds return 0; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds #endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */ 2581da177e4SLinus Torvalds 259454804abSSerge E. Hallyn static struct rb_node *__key_user_next(struct rb_node *n) 260454804abSSerge E. Hallyn { 261454804abSSerge E. Hallyn while (n) { 262454804abSSerge E. Hallyn struct key_user *user = rb_entry(n, struct key_user, node); 263454804abSSerge E. Hallyn if (user->user_ns == current_user_ns()) 264454804abSSerge E. Hallyn break; 265454804abSSerge E. Hallyn n = rb_next(n); 266454804abSSerge E. Hallyn } 267454804abSSerge E. Hallyn return n; 268454804abSSerge E. Hallyn } 269454804abSSerge E. Hallyn 270454804abSSerge E. Hallyn static struct rb_node *key_user_next(struct rb_node *n) 271454804abSSerge E. Hallyn { 272454804abSSerge E. Hallyn return __key_user_next(rb_next(n)); 273454804abSSerge E. Hallyn } 274454804abSSerge E. Hallyn 275454804abSSerge E. Hallyn static struct rb_node *key_user_first(struct rb_root *r) 276454804abSSerge E. Hallyn { 277454804abSSerge E. Hallyn struct rb_node *n = rb_first(r); 278454804abSSerge E. Hallyn return __key_user_next(n); 279454804abSSerge E. Hallyn } 280*7b1b9164SDavid Howells 2811da177e4SLinus Torvalds /*****************************************************************************/ 2821da177e4SLinus Torvalds /* 2831da177e4SLinus Torvalds * implement "/proc/key-users" to provides a list of the key users 2841da177e4SLinus Torvalds */ 2851da177e4SLinus Torvalds static int proc_key_users_open(struct inode *inode, struct file *file) 2861da177e4SLinus Torvalds { 2871da177e4SLinus Torvalds return seq_open(file, &proc_key_users_ops); 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) 29186abcf9cSJames Morris __acquires(key_user_lock) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds struct rb_node *_p; 2941da177e4SLinus Torvalds loff_t pos = *_pos; 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds spin_lock(&key_user_lock); 2971da177e4SLinus Torvalds 298454804abSSerge E. Hallyn _p = key_user_first(&key_user_tree); 2991da177e4SLinus Torvalds while (pos > 0 && _p) { 3001da177e4SLinus Torvalds pos--; 301454804abSSerge E. Hallyn _p = key_user_next(_p); 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds return _p; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds (*_pos)++; 310454804abSSerge E. Hallyn return key_user_next((struct rb_node *) v); 3111da177e4SLinus Torvalds } 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds static void proc_key_users_stop(struct seq_file *p, void *v) 31486abcf9cSJames Morris __releases(key_user_lock) 3151da177e4SLinus Torvalds { 3161da177e4SLinus Torvalds spin_unlock(&key_user_lock); 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds static int proc_key_users_show(struct seq_file *m, void *v) 3201da177e4SLinus Torvalds { 3211da177e4SLinus Torvalds struct rb_node *_p = v; 3221da177e4SLinus Torvalds struct key_user *user = rb_entry(_p, struct key_user, node); 3230b77f5bfSDavid Howells unsigned maxkeys = (user->uid == 0) ? 3240b77f5bfSDavid Howells key_quota_root_maxkeys : key_quota_maxkeys; 3250b77f5bfSDavid Howells unsigned maxbytes = (user->uid == 0) ? 3260b77f5bfSDavid Howells key_quota_root_maxbytes : key_quota_maxbytes; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n", 3291da177e4SLinus Torvalds user->uid, 3301da177e4SLinus Torvalds atomic_read(&user->usage), 3311da177e4SLinus Torvalds atomic_read(&user->nkeys), 3321da177e4SLinus Torvalds atomic_read(&user->nikeys), 3331da177e4SLinus Torvalds user->qnkeys, 3340b77f5bfSDavid Howells maxkeys, 3351da177e4SLinus Torvalds user->qnbytes, 3360b77f5bfSDavid Howells maxbytes); 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds return 0; 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds } 341