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