linux/kernel/ucount.c
<<
>>
Prefs
   1/*
   2 *  This program is free software; you can redistribute it and/or
   3 *  modify it under the terms of the GNU General Public License as
   4 *  published by the Free Software Foundation, version 2 of the
   5 *  License.
   6 */
   7
   8#include <linux/stat.h>
   9#include <linux/sysctl.h>
  10#include <linux/slab.h>
  11#include <linux/cred.h>
  12#include <linux/hash.h>
  13#include <linux/user_namespace.h>
  14
  15#define UCOUNTS_HASHTABLE_BITS 10
  16static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
  17static DEFINE_SPINLOCK(ucounts_lock);
  18
  19#define ucounts_hashfn(ns, uid)                                         \
  20        hash_long((unsigned long)__kuid_val(uid) + (unsigned long)(ns), \
  21                  UCOUNTS_HASHTABLE_BITS)
  22#define ucounts_hashentry(ns, uid)      \
  23        (ucounts_hashtable + ucounts_hashfn(ns, uid))
  24
  25
  26#ifdef CONFIG_SYSCTL
  27static struct ctl_table_set *
  28set_lookup(struct ctl_table_root *root)
  29{
  30        return &current_user_ns()->set;
  31}
  32
  33static int set_is_seen(struct ctl_table_set *set)
  34{
  35        return &current_user_ns()->set == set;
  36}
  37
  38static int set_permissions(struct ctl_table_header *head,
  39                                  struct ctl_table *table)
  40{
  41        struct user_namespace *user_ns =
  42                container_of(head->set, struct user_namespace, set);
  43        int mode;
  44
  45        /* Allow users with CAP_SYS_RESOURCE unrestrained access */
  46        if (ns_capable(user_ns, CAP_SYS_RESOURCE))
  47                mode = (table->mode & S_IRWXU) >> 6;
  48        else
  49        /* Allow all others at most read-only access */
  50                mode = table->mode & S_IROTH;
  51        return (mode << 6) | (mode << 3) | mode;
  52}
  53
  54static struct ctl_table_root set_root = {
  55        .lookup = set_lookup,
  56        .permissions = set_permissions,
  57};
  58
  59static int zero = 0;
  60static int int_max = INT_MAX;
  61#define UCOUNT_ENTRY(name)                              \
  62        {                                               \
  63                .procname       = name,                 \
  64                .maxlen         = sizeof(int),          \
  65                .mode           = 0644,                 \
  66                .proc_handler   = proc_dointvec_minmax, \
  67                .extra1         = &zero,                \
  68                .extra2         = &int_max,             \
  69        }
  70static struct ctl_table user_table[] = {
  71        UCOUNT_ENTRY("max_user_namespaces"),
  72        UCOUNT_ENTRY("max_pid_namespaces"),
  73        UCOUNT_ENTRY("max_uts_namespaces"),
  74        UCOUNT_ENTRY("max_ipc_namespaces"),
  75        UCOUNT_ENTRY("max_net_namespaces"),
  76        UCOUNT_ENTRY("max_mnt_namespaces"),
  77        UCOUNT_ENTRY("max_cgroup_namespaces"),
  78#ifdef CONFIG_INOTIFY_USER
  79        UCOUNT_ENTRY("max_inotify_instances"),
  80        UCOUNT_ENTRY("max_inotify_watches"),
  81#endif
  82        { }
  83};
  84#endif /* CONFIG_SYSCTL */
  85
  86bool setup_userns_sysctls(struct user_namespace *ns)
  87{
  88#ifdef CONFIG_SYSCTL
  89        struct ctl_table *tbl;
  90        setup_sysctl_set(&ns->set, &set_root, set_is_seen);
  91        tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL);
  92        if (tbl) {
  93                int i;
  94                for (i = 0; i < UCOUNT_COUNTS; i++) {
  95                        tbl[i].data = &ns->ucount_max[i];
  96                }
  97                ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl);
  98        }
  99        if (!ns->sysctls) {
 100                kfree(tbl);
 101                retire_sysctl_set(&ns->set);
 102                return false;
 103        }
 104#endif
 105        return true;
 106}
 107
 108void retire_userns_sysctls(struct user_namespace *ns)
 109{
 110#ifdef CONFIG_SYSCTL
 111        struct ctl_table *tbl;
 112
 113        tbl = ns->sysctls->ctl_table_arg;
 114        unregister_sysctl_table(ns->sysctls);
 115        retire_sysctl_set(&ns->set);
 116        kfree(tbl);
 117#endif
 118}
 119
 120static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struct hlist_head *hashent)
 121{
 122        struct ucounts *ucounts;
 123
 124        hlist_for_each_entry(ucounts, hashent, node) {
 125                if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns))
 126                        return ucounts;
 127        }
 128        return NULL;
 129}
 130
 131static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
 132{
 133        struct hlist_head *hashent = ucounts_hashentry(ns, uid);
 134        struct ucounts *ucounts, *new;
 135
 136        spin_lock_irq(&ucounts_lock);
 137        ucounts = find_ucounts(ns, uid, hashent);
 138        if (!ucounts) {
 139                spin_unlock_irq(&ucounts_lock);
 140
 141                new = kzalloc(sizeof(*new), GFP_KERNEL);
 142                if (!new)
 143                        return NULL;
 144
 145                new->ns = ns;
 146                new->uid = uid;
 147                new->count = 0;
 148
 149                spin_lock_irq(&ucounts_lock);
 150                ucounts = find_ucounts(ns, uid, hashent);
 151                if (ucounts) {
 152                        kfree(new);
 153                } else {
 154                        hlist_add_head(&new->node, hashent);
 155                        ucounts = new;
 156                }
 157        }
 158        if (ucounts->count == INT_MAX)
 159                ucounts = NULL;
 160        else
 161                ucounts->count += 1;
 162        spin_unlock_irq(&ucounts_lock);
 163        return ucounts;
 164}
 165
 166static void put_ucounts(struct ucounts *ucounts)
 167{
 168        unsigned long flags;
 169
 170        spin_lock_irqsave(&ucounts_lock, flags);
 171        ucounts->count -= 1;
 172        if (!ucounts->count)
 173                hlist_del_init(&ucounts->node);
 174        else
 175                ucounts = NULL;
 176        spin_unlock_irqrestore(&ucounts_lock, flags);
 177
 178        kfree(ucounts);
 179}
 180
 181static inline bool atomic_inc_below(atomic_t *v, int u)
 182{
 183        int c, old;
 184        c = atomic_read(v);
 185        for (;;) {
 186                if (unlikely(c >= u))
 187                        return false;
 188                old = atomic_cmpxchg(v, c, c+1);
 189                if (likely(old == c))
 190                        return true;
 191                c = old;
 192        }
 193}
 194
 195struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
 196                           enum ucount_type type)
 197{
 198        struct ucounts *ucounts, *iter, *bad;
 199        struct user_namespace *tns;
 200        ucounts = get_ucounts(ns, uid);
 201        for (iter = ucounts; iter; iter = tns->ucounts) {
 202                int max;
 203                tns = iter->ns;
 204                max = READ_ONCE(tns->ucount_max[type]);
 205                if (!atomic_inc_below(&iter->ucount[type], max))
 206                        goto fail;
 207        }
 208        return ucounts;
 209fail:
 210        bad = iter;
 211        for (iter = ucounts; iter != bad; iter = iter->ns->ucounts)
 212                atomic_dec(&iter->ucount[type]);
 213
 214        put_ucounts(ucounts);
 215        return NULL;
 216}
 217
 218void dec_ucount(struct ucounts *ucounts, enum ucount_type type)
 219{
 220        struct ucounts *iter;
 221        for (iter = ucounts; iter; iter = iter->ns->ucounts) {
 222                int dec = atomic_dec_if_positive(&iter->ucount[type]);
 223                WARN_ON_ONCE(dec < 0);
 224        }
 225        put_ucounts(ucounts);
 226}
 227
 228static __init int user_namespace_sysctl_init(void)
 229{
 230#ifdef CONFIG_SYSCTL
 231        static struct ctl_table_header *user_header;
 232        static struct ctl_table empty[1];
 233        /*
 234         * It is necessary to register the user directory in the
 235         * default set so that registrations in the child sets work
 236         * properly.
 237         */
 238        user_header = register_sysctl("user", empty);
 239        kmemleak_ignore(user_header);
 240        BUG_ON(!user_header);
 241        BUG_ON(!setup_userns_sysctls(&init_user_ns));
 242#endif
 243        return 0;
 244}
 245subsys_initcall(user_namespace_sysctl_init);
 246