Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • 603f6b6
  • /
  • keys
  • /
  • proc.c
Raw File Download
Permalinks

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge Iframe embedding
swh:1:cnt:217b6855e815cb851153fa08646d2bf145cee579
directory badge Iframe embedding
swh:1:dir:d6bef74ed75a91c17abb97fcd9eec4e5e2188335
Citations

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
proc.c
/* procfs files for key database enumeration
 *
 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/errno.h>
#include "internal.h"

#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
static int proc_keys_open(struct inode *inode, struct file *file);
static void *proc_keys_start(struct seq_file *p, loff_t *_pos);
static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos);
static void proc_keys_stop(struct seq_file *p, void *v);
static int proc_keys_show(struct seq_file *m, void *v);

static const struct seq_operations proc_keys_ops = {
	.start	= proc_keys_start,
	.next	= proc_keys_next,
	.stop	= proc_keys_stop,
	.show	= proc_keys_show,
};

static const struct file_operations proc_keys_fops = {
	.open		= proc_keys_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
#endif

static int proc_key_users_open(struct inode *inode, struct file *file);
static void *proc_key_users_start(struct seq_file *p, loff_t *_pos);
static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos);
static void proc_key_users_stop(struct seq_file *p, void *v);
static int proc_key_users_show(struct seq_file *m, void *v);

static const struct seq_operations proc_key_users_ops = {
	.start	= proc_key_users_start,
	.next	= proc_key_users_next,
	.stop	= proc_key_users_stop,
	.show	= proc_key_users_show,
};

static const struct file_operations proc_key_users_fops = {
	.open		= proc_key_users_open,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};

/*
 * Declare the /proc files.
 */
static int __init key_proc_init(void)
{
	struct proc_dir_entry *p;

#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
	p = proc_create("keys", 0, NULL, &proc_keys_fops);
	if (!p)
		panic("Cannot create /proc/keys\n");
#endif

	p = proc_create("key-users", 0, NULL, &proc_key_users_fops);
	if (!p)
		panic("Cannot create /proc/key-users\n");

	return 0;
}

__initcall(key_proc_init);

/*
 * Implement "/proc/keys" to provide a list of the keys on the system that
 * grant View permission to the caller.
 */
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS

static struct rb_node *key_serial_next(struct seq_file *p, struct rb_node *n)
{
	struct user_namespace *user_ns = seq_user_ns(p);

	n = rb_next(n);
	while (n) {
		struct key *key = rb_entry(n, struct key, serial_node);
		if (kuid_has_mapping(user_ns, key->user->uid))
			break;
		n = rb_next(n);
	}
	return n;
}

static int proc_keys_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &proc_keys_ops);
}

static struct key *find_ge_key(struct seq_file *p, key_serial_t id)
{
	struct user_namespace *user_ns = seq_user_ns(p);
	struct rb_node *n = key_serial_tree.rb_node;
	struct key *minkey = NULL;

	while (n) {
		struct key *key = rb_entry(n, struct key, serial_node);
		if (id < key->serial) {
			if (!minkey || minkey->serial > key->serial)
				minkey = key;
			n = n->rb_left;
		} else if (id > key->serial) {
			n = n->rb_right;
		} else {
			minkey = key;
			break;
		}
		key = NULL;
	}

	if (!minkey)
		return NULL;

	for (;;) {
		if (kuid_has_mapping(user_ns, minkey->user->uid))
			return minkey;
		n = rb_next(&minkey->serial_node);
		if (!n)
			return NULL;
		minkey = rb_entry(n, struct key, serial_node);
	}
}

static void *proc_keys_start(struct seq_file *p, loff_t *_pos)
	__acquires(key_serial_lock)
{
	key_serial_t pos = *_pos;
	struct key *key;

	spin_lock(&key_serial_lock);

	if (*_pos > INT_MAX)
		return NULL;
	key = find_ge_key(p, pos);
	if (!key)
		return NULL;
	*_pos = key->serial;
	return &key->serial_node;
}

static inline key_serial_t key_node_serial(struct rb_node *n)
{
	struct key *key = rb_entry(n, struct key, serial_node);
	return key->serial;
}

static void *proc_keys_next(struct seq_file *p, void *v, loff_t *_pos)
{
	struct rb_node *n;

	n = key_serial_next(p, v);
	if (n)
		*_pos = key_node_serial(n);
	return n;
}

static void proc_keys_stop(struct seq_file *p, void *v)
	__releases(key_serial_lock)
{
	spin_unlock(&key_serial_lock);
}

static int proc_keys_show(struct seq_file *m, void *v)
{
	const struct cred *cred = current_cred();
	struct rb_node *_p = v;
	struct key *key = rb_entry(_p, struct key, serial_node);
	struct timespec now;
	unsigned long timo;
	key_ref_t key_ref, skey_ref;
	char xbuf[12];
	int rc;

	key_ref = make_key_ref(key, 0);

	/* determine if the key is possessed by this process (a test we can
	 * skip if the key does not indicate the possessor can view it
	 */
	if (key->perm & KEY_POS_VIEW) {
		skey_ref = search_my_process_keyrings(key->type, key,
						      lookup_user_key_possessed,
						      true, cred);
		if (!IS_ERR(skey_ref)) {
			key_ref_put(skey_ref);
			key_ref = make_key_ref(key, 1);
		}
	}

	/* check whether the current task is allowed to view the key (assuming
	 * non-possession)
	 * - the caller holds a spinlock, and thus the RCU read lock, making our
	 *   access to __current_cred() safe
	 */
	rc = key_task_permission(key_ref, cred, KEY_VIEW);
	if (rc < 0)
		return 0;

	now = current_kernel_time();

	rcu_read_lock();

	/* come up with a suitable timeout value */
	if (key->expiry == 0) {
		memcpy(xbuf, "perm", 5);
	} else if (now.tv_sec >= key->expiry) {
		memcpy(xbuf, "expd", 5);
	} else {
		timo = key->expiry - now.tv_sec;

		if (timo < 60)
			sprintf(xbuf, "%lus", timo);
		else if (timo < 60*60)
			sprintf(xbuf, "%lum", timo / 60);
		else if (timo < 60*60*24)
			sprintf(xbuf, "%luh", timo / (60*60));
		else if (timo < 60*60*24*7)
			sprintf(xbuf, "%lud", timo / (60*60*24));
		else
			sprintf(xbuf, "%luw", timo / (60*60*24*7));
	}

#define showflag(KEY, LETTER, FLAG) \
	(test_bit(FLAG,	&(KEY)->flags) ? LETTER : '-')

	seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ",
		   key->serial,
		   showflag(key, 'I', KEY_FLAG_INSTANTIATED),
		   showflag(key, 'R', KEY_FLAG_REVOKED),
		   showflag(key, 'D', KEY_FLAG_DEAD),
		   showflag(key, 'Q', KEY_FLAG_IN_QUOTA),
		   showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
		   showflag(key, 'N', KEY_FLAG_NEGATIVE),
		   showflag(key, 'i', KEY_FLAG_INVALIDATED),
		   atomic_read(&key->usage),
		   xbuf,
		   key->perm,
		   from_kuid_munged(seq_user_ns(m), key->uid),
		   from_kgid_munged(seq_user_ns(m), key->gid),
		   key->type->name);

#undef showflag

	if (key->type->describe)
		key->type->describe(key, m);
	seq_putc(m, '\n');

	rcu_read_unlock();
	return 0;
}

#endif /* CONFIG_KEYS_DEBUG_PROC_KEYS */

static struct rb_node *__key_user_next(struct user_namespace *user_ns, struct rb_node *n)
{
	while (n) {
		struct key_user *user = rb_entry(n, struct key_user, node);
		if (kuid_has_mapping(user_ns, user->uid))
			break;
		n = rb_next(n);
	}
	return n;
}

static struct rb_node *key_user_next(struct user_namespace *user_ns, struct rb_node *n)
{
	return __key_user_next(user_ns, rb_next(n));
}

static struct rb_node *key_user_first(struct user_namespace *user_ns, struct rb_root *r)
{
	struct rb_node *n = rb_first(r);
	return __key_user_next(user_ns, n);
}

/*
 * Implement "/proc/key-users" to provides a list of the key users and their
 * quotas.
 */
static int proc_key_users_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &proc_key_users_ops);
}

static void *proc_key_users_start(struct seq_file *p, loff_t *_pos)
	__acquires(key_user_lock)
{
	struct rb_node *_p;
	loff_t pos = *_pos;

	spin_lock(&key_user_lock);

	_p = key_user_first(seq_user_ns(p), &key_user_tree);
	while (pos > 0 && _p) {
		pos--;
		_p = key_user_next(seq_user_ns(p), _p);
	}

	return _p;
}

static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos)
{
	(*_pos)++;
	return key_user_next(seq_user_ns(p), (struct rb_node *)v);
}

static void proc_key_users_stop(struct seq_file *p, void *v)
	__releases(key_user_lock)
{
	spin_unlock(&key_user_lock);
}

static int proc_key_users_show(struct seq_file *m, void *v)
{
	struct rb_node *_p = v;
	struct key_user *user = rb_entry(_p, struct key_user, node);
	unsigned maxkeys = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
		key_quota_root_maxkeys : key_quota_maxkeys;
	unsigned maxbytes = uid_eq(user->uid, GLOBAL_ROOT_UID) ?
		key_quota_root_maxbytes : key_quota_maxbytes;

	seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
		   from_kuid_munged(seq_user_ns(m), user->uid),
		   atomic_read(&user->usage),
		   atomic_read(&user->nkeys),
		   atomic_read(&user->nikeys),
		   user->qnkeys,
		   maxkeys,
		   user->qnbytes,
		   maxbytes);

	return 0;
}

back to top

Software Heritage — Copyright (C) 2015–2025, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Contact— JavaScript license information— Web API