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