cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

proc.c (7930B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* procfs files for key database enumeration
      3 *
      4 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/sched.h>
     10#include <linux/fs.h>
     11#include <linux/proc_fs.h>
     12#include <linux/seq_file.h>
     13#include <asm/errno.h>
     14#include "internal.h"
     15
     16static void *proc_keys_start(struct seq_file *p, loff_t *_pos);
     17static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
     18static void proc_keys_stop(struct seq_file *p, void *v);
     19static int proc_keys_show(struct seq_file *m, void *v);
     20
     21static const struct seq_operations proc_keys_ops = {
     22	.start	= proc_keys_start,
     23	.next	= proc_keys_next,
     24	.stop	= proc_keys_stop,
     25	.show	= proc_keys_show,
     26};
     27
     28static void *proc_key_users_start(struct seq_file *p, loff_t *_pos);
     29static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos);
     30static void proc_key_users_stop(struct seq_file *p, void *v);
     31static int proc_key_users_show(struct seq_file *m, void *v);
     32
     33static const struct seq_operations proc_key_users_ops = {
     34	.start	= proc_key_users_start,
     35	.next	= proc_key_users_next,
     36	.stop	= proc_key_users_stop,
     37	.show	= proc_key_users_show,
     38};
     39
     40/*
     41 * Declare the /proc files.
     42 */
     43static int __init key_proc_init(void)
     44{
     45	struct proc_dir_entry *p;
     46
     47	p = proc_create_seq("keys", 0, NULL, &proc_keys_ops);
     48	if (!p)
     49		panic("Cannot create /proc/keys\n");
     50
     51	p = proc_create_seq("key-users", 0, NULL, &proc_key_users_ops);
     52	if (!p)
     53		panic("Cannot create /proc/key-users\n");
     54
     55	return 0;
     56}
     57
     58__initcall(key_proc_init);
     59
     60/*
     61 * Implement "/proc/keys" to provide a list of the keys on the system that
     62 * grant View permission to the caller.
     63 */
     64static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
     65{
     66	struct user_namespace *user_ns = seq_user_ns(p);
     67
     68	n = rb_next(n);
     69	while (n) {
     70		struct key *key = rb_entry(n, struct key, serial_node);
     71		if (kuid_has_mapping(user_ns, key->user->uid))
     72			break;
     73		n = rb_next(n);
     74	}
     75	return n;
     76}
     77
     78static struct key *find_ge_key(struct seq_file *p, key_serial_t id)
     79{
     80	struct user_namespace *user_ns = seq_user_ns(p);
     81	struct rb_node *n = key_serial_tree.rb_node;
     82	struct key *minkey = NULL;
     83
     84	while (n) {
     85		struct key *key = rb_entry(n, struct key, serial_node);
     86		if (id < key->serial) {
     87			if (!minkey || minkey->serial > key->serial)
     88				minkey = key;
     89			n = n->rb_left;
     90		} else if (id > key->serial) {
     91			n = n->rb_right;
     92		} else {
     93			minkey = key;
     94			break;
     95		}
     96		key = NULL;
     97	}
     98
     99	if (!minkey)
    100		return NULL;
    101
    102	for (;;) {
    103		if (kuid_has_mapping(user_ns, minkey->user->uid))
    104			return minkey;
    105		n = rb_next(&minkey->serial_node);
    106		if (!n)
    107			return NULL;
    108		minkey = rb_entry(n, struct key, serial_node);
    109	}
    110}
    111
    112static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
    113	__acquires(key_serial_lock)
    114{
    115	key_serial_t pos = *_pos;
    116	struct key *key;
    117
    118	spin_lock(&key_serial_lock);
    119
    120	if (*_pos > INT_MAX)
    121		return NULL;
    122	key = find_ge_key(p, pos);
    123	if (!key)
    124		return NULL;
    125	*_pos = key->serial;
    126	return &key->serial_node;
    127}
    128
    129static inline key_serial_t key_node_serial(struct rb_node *n)
    130{
    131	struct key *key = rb_entry(n, struct key, serial_node);
    132	return key->serial;
    133}
    134
    135static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
    136{
    137	struct rb_node *n;
    138
    139	n = key_serial_next(p, v);
    140	if (n)
    141		*_pos = key_node_serial(n);
    142	else
    143		(*_pos)++;
    144	return n;
    145}
    146
    147static void proc_keys_stop(struct seq_file *p, void *v)
    148	__releases(key_serial_lock)
    149{
    150	spin_unlock(&key_serial_lock);
    151}
    152
    153static int proc_keys_show(struct seq_file *m, void *v)
    154{
    155	struct rb_node *_p = v;
    156	struct key *key = rb_entry(_p, struct key, serial_node);
    157	unsigned long flags;
    158	key_ref_t key_ref, skey_ref;
    159	time64_t now, expiry;
    160	char xbuf[16];
    161	short state;
    162	u64 timo;
    163	int rc;
    164
    165	struct keyring_search_context ctx = {
    166		.index_key		= key->index_key,
    167		.cred			= m->file->f_cred,
    168		.match_data.cmp		= lookup_user_key_possessed,
    169		.match_data.raw_data	= key,
    170		.match_data.lookup_type	= KEYRING_SEARCH_LOOKUP_DIRECT,
    171		.flags			= (KEYRING_SEARCH_NO_STATE_CHECK |
    172					   KEYRING_SEARCH_RECURSE),
    173	};
    174
    175	key_ref = make_key_ref(key, 0);
    176
    177	/* determine if the key is possessed by this process (a test we can
    178	 * skip if the key does not indicate the possessor can view it
    179	 */
    180	if (key->perm & KEY_POS_VIEW) {
    181		rcu_read_lock();
    182		skey_ref = search_cred_keyrings_rcu(&ctx);
    183		rcu_read_unlock();
    184		if (!IS_ERR(skey_ref)) {
    185			key_ref_put(skey_ref);
    186			key_ref = make_key_ref(key, 1);
    187		}
    188	}
    189
    190	/* check whether the current task is allowed to view the key */
    191	rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW);
    192	if (rc < 0)
    193		return 0;
    194
    195	now = ktime_get_real_seconds();
    196
    197	rcu_read_lock();
    198
    199	/* come up with a suitable timeout value */
    200	expiry = READ_ONCE(key->expiry);
    201	if (expiry == 0) {
    202		memcpy(xbuf, "perm", 5);
    203	} else if (now >= expiry) {
    204		memcpy(xbuf, "expd", 5);
    205	} else {
    206		timo = expiry - now;
    207
    208		if (timo < 60)
    209			sprintf(xbuf, "%llus", timo);
    210		else if (timo < 60*60)
    211			sprintf(xbuf, "%llum", div_u64(timo, 60));
    212		else if (timo < 60*60*24)
    213			sprintf(xbuf, "%lluh", div_u64(timo, 60 * 60));
    214		else if (timo < 60*60*24*7)
    215			sprintf(xbuf, "%llud", div_u64(timo, 60 * 60 * 24));
    216		else
    217			sprintf(xbuf, "%lluw", div_u64(timo, 60 * 60 * 24 * 7));
    218	}
    219
    220	state = key_read_state(key);
    221
    222#define showflag(FLAGS, LETTER, FLAG) \
    223	((FLAGS & (1 << FLAG)) ? LETTER : '-')
    224
    225	flags = READ_ONCE(key->flags);
    226	seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
    227		   key->serial,
    228		   state != KEY_IS_UNINSTANTIATED ? 'I' : '-',
    229		   showflag(flags, 'R', KEY_FLAG_REVOKED),
    230		   showflag(flags, 'D', KEY_FLAG_DEAD),
    231		   showflag(flags, 'Q', KEY_FLAG_IN_QUOTA),
    232		   showflag(flags, 'U', KEY_FLAG_USER_CONSTRUCT),
    233		   state < 0 ? 'N' : '-',
    234		   showflag(flags, 'i', KEY_FLAG_INVALIDATED),
    235		   refcount_read(&key->usage),
    236		   xbuf,
    237		   key->perm,
    238		   from_kuid_munged(seq_user_ns(m), key->uid),
    239		   from_kgid_munged(seq_user_ns(m), key->gid),
    240		   key->type->name);
    241
    242#undef showflag
    243
    244	if (key->type->describe)
    245		key->type->describe(key, m);
    246	seq_putc(m, '\n');
    247
    248	rcu_read_unlock();
    249	return 0;
    250}
    251
    252static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
    253{
    254	while (n) {
    255		struct key_user *user = rb_entry(n, struct key_user, node);
    256		if (kuid_has_mapping(user_ns, user->uid))
    257			break;
    258		n = rb_next(n);
    259	}
    260	return n;
    261}
    262
    263static struct rb_node *key_user_next(struct user_namespace *user_ns, struct rb_node *n)
    264{
    265	return __key_user_next(user_ns, rb_next(n));
    266}
    267
    268static struct rb_node *key_user_first(struct user_namespace *user_ns, struct rb_root *r)
    269{
    270	struct rb_node *n = rb_first(r);
    271	return __key_user_next(user_ns, n);
    272}
    273
    274static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
    275	__acquires(key_user_lock)
    276{
    277	struct rb_node *_p;
    278	loff_t pos = *_pos;
    279
    280	spin_lock(&key_user_lock);
    281
    282	_p = key_user_first(seq_user_ns(p), &key_user_tree);
    283	while (pos > 0 && _p) {
    284		pos--;
    285		_p = key_user_next(seq_user_ns(p), _p);
    286	}
    287
    288	return _p;
    289}
    290
    291static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
    292{
    293	(*_pos)++;
    294	return key_user_next(seq_user_ns(p), (struct rb_node *)v);
    295}
    296
    297static void proc_key_users_stop(struct seq_file *p, void *v)
    298	__releases(key_user_lock)
    299{
    300	spin_unlock(&key_user_lock);
    301}
    302
    303static int proc_key_users_show(struct seq_file *m, void *v)
    304{
    305	struct rb_node *_p = v;
    306	struct key_user *user = rb_entry(_p, struct key_user, node);
    307	unsigned maxkeys = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
    308		key_quota_root_maxkeys : key_quota_maxkeys;
    309	unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
    310		key_quota_root_maxbytes : key_quota_maxbytes;
    311
    312	seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
    313		   from_kuid_munged(seq_user_ns(m), user->uid),
    314		   refcount_read(&user->usage),
    315		   atomic_read(&user->nkeys),
    316		   atomic_read(&user->nikeys),
    317		   user->qnkeys,
    318		   maxkeys,
    319		   user->qnbytes,
    320		   maxbytes);
    321
    322	return 0;
    323}