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