[PATCH] kernel: show current values of ucounts
Kees Cook
keescook at chromium.org
Thu Aug 11 19:05:12 UTC 2016
On Thu, Aug 11, 2016 at 12:02 AM, Andrei Vagin <avagin at openvz.org> wrote:
> This patch adds /proc/ucounts where all non-zero ucounts for a current
> userns are shown.
Eric would have a better sense of this, but I think we would normally
avoid putting something in the top-level /proc directory, especially
for namespace things (which IIUC usually appear in /proc/$pid/ns/).
Also, this should describe what ucounts are for people unfamiliar with
them. (i.e. this commit message doesn't really contain a detailed
description of what's being added.)
And finally, any changes to /proc need an associated entry in
Documentation/filesystems/proc.txt
>
> $ cat /proc/ucounts
> user: 1000 1
> net: 1000 1
> mnt: 1000 2
> mnt: 0 10
> cgroup: 0 1
>
> There are three columns: type, uid, value.
>
> Signed-off-by: Andrei Vagin <avagin at openvz.org>
> ---
> kernel/ucount.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 121 insertions(+)
>
> diff --git a/kernel/ucount.c b/kernel/ucount.c
> index 9d20d5d..02a7b7f 100644
> --- a/kernel/ucount.c
> +++ b/kernel/ucount.c
> @@ -9,6 +9,8 @@
> #include <linux/sysctl.h>
> #include <linux/slab.h>
> #include <linux/hash.h>
> +#include <linux/seq_file.h>
> +#include <linux/proc_fs.h>
> #include <linux/user_namespace.h>
>
> #define UCOUNTS_HASHTABLE_BITS 10
> @@ -232,4 +234,123 @@ static __init int user_namespace_sysctl_init(void)
> }
> subsys_initcall(user_namespace_sysctl_init);
>
> +#ifdef CONFIG_PROC_FS
> +struct ucounts_iterator {
> + int hash;
> +};
> +
> +static void *ucounts_start(struct seq_file *f, loff_t *pos)
> +{
> + struct ucounts_iterator *iter = f->private;
> + struct user_namespace *ns = current_user_ns();
> + int h, i = 0;
> +
> + spin_lock(&ucounts_lock);
> + for (h = 0; h < (1 << UCOUNTS_HASHTABLE_BITS); h++) {
> + struct ucounts *ucounts;
> +
> + hlist_for_each_entry(ucounts, &ucounts_hashtable[h], node) {
> + if (ucounts->ns != ns)
> + continue;
> + if (i++ < *pos)
> + continue;
> +
> + iter->hash = h;
> +
> + return ucounts;
> + }
> + }
> +
> + return NULL;
> +}
> +
> +static void ucounts_stop(struct seq_file *f, void *v)
> +{
> + spin_unlock(&ucounts_lock);
> +}
I don't see where ucounts_lock is defined, but even still, holding a
spinlock across start/stop will provide a way DoS anyone else using
that lock. And sparse will yell at you very loudly for the unbalanced
locking too. :)
> +static void *ucounts_next(struct seq_file *f, void *v, loff_t *pos)
> +{
> + struct ucounts_iterator *iter = f->private;
> + struct user_namespace *ns = current_user_ns();
> + struct ucounts *ucounts = v;
> + int h;
> +
> + ++*pos;
> +
> + for (h = iter->hash; h < (1 << UCOUNTS_HASHTABLE_BITS); h++) {
> + struct hlist_node *node;
> +
> + if (ucounts == NULL) {
> + node = ucounts_hashtable[h].first;
> + iter->hash = h;
> + } else
> + node = ucounts->node.next;
> +
> + ucounts = hlist_entry(node, struct ucounts, node);
> +
> + hlist_for_each_entry_from(ucounts, node) {
> + if (ucounts->ns != ns)
> + continue;
> +
> + return ucounts;
> + }
> +
> + ucounts = NULL;
> + }
> +
> + return NULL;
> +}
> +
> +static int ucounts_show(struct seq_file *f, void *v)
> +{
> + static const char * const ns_strs[] = {
> + "user", "pid", "uts", "ipc",
> + "net", "mnt", "cgroup", NULL
> + };
> + struct user_namespace *ns = current_user_ns();
> + struct ucounts *ucounts = v;
> + uid_t uid;
> + int i;
> +
> + uid = from_kuid_munged(ns, ucounts->uid);
> +
> + for (i = 0; ns_strs[i]; i++) {
> + int val = atomic_read(&ucounts->ucount[i]);
> +
> + if (val == 0)
> + continue;
> +
> + seq_printf(f, "%s:\t%10u\t%10d\n", ns_strs[i], uid, val);
> + }
>
> + return 0;
> +}
> +
> +static const struct seq_operations ucounts_seq_operations = {
> + .start = ucounts_start,
> + .next = ucounts_next,
> + .stop = ucounts_stop,
> + .show = ucounts_show,
> +};
> +
> +static int ucounts_open(struct inode *inode, struct file *filp)
> +{
> + return seq_open_private(filp, &ucounts_seq_operations,
> + sizeof(struct ucounts_iterator));
> +}
> +
> +static const struct file_operations proc_ucounts_operations = {
> + .open = ucounts_open,
> + .read = seq_read,
> + .llseek = seq_lseek,
> + .release = seq_release_private,
> +};
> +
> +static int __init proc_ucounts_init(void)
> +{
> + proc_create("ucounts", 0, NULL, &proc_ucounts_operations);
> + return 0;
> +}
> +fs_initcall(proc_ucounts_init);
> +#endif /* CONFIG_PROC_FS */
> --
> 2.5.5
>
-Kees
--
Kees Cook
Nexus Security
More information about the Containers
mailing list