user_struct contains per-user counters like processes, files, sigpending etc which we wouldn't like to share across different namespaces. Make per-userns uid hastable instead of global. This is partial revert of the 7b44ab978b77a ("userns: Disassociate user_struct from the user_namespace.")
Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com> --- include/linux/sched/user.h | 1 + include/linux/user_namespace.h | 4 ++++ kernel/user.c | 22 +++++++++++++--------- kernel/user_namespace.c | 13 +++++++++++++ 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h index 9a9536fd4fe3..4bf5a723f138 100644 --- a/include/linux/sched/user.h +++ b/include/linux/sched/user.h @@ -60,6 +60,7 @@ extern struct user_struct *find_user(kuid_t); extern struct user_struct root_user; #define INIT_USER (&root_user) +extern struct user_struct * alloc_uid_ns(struct user_namespace *ns, kuid_t); /* per-UID process charging. */ extern struct user_struct * alloc_uid(kuid_t); diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index b004d5aeba1f..30493179b756 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -15,6 +15,9 @@ #define UID_GID_MAP_MAX_BASE_EXTENTS 5 #define UID_GID_MAP_MAX_EXTENTS 340 +#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7) +#define UIDHASH_SZ (1 << UIDHASH_BITS) + struct uid_gid_extent { u32 first; u32 lower_first; @@ -73,6 +76,7 @@ struct user_namespace { struct uid_gid_map gid_map; struct uid_gid_map projid_map; atomic_t count; + struct hlist_head uidhash_table[UIDHASH_SZ]; struct user_namespace *parent; int level; kuid_t owner; diff --git a/kernel/user.c b/kernel/user.c index 0df9b1640b2a..f9f540484499 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -8,6 +8,7 @@ * able to have per-user limits for system resources. */ +#include <linux/cred.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/slab.h> @@ -74,14 +75,11 @@ EXPORT_SYMBOL_GPL(init_user_ns); * when changing user ID's (ie setuid() and friends). */ -#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7) -#define UIDHASH_SZ (1 << UIDHASH_BITS) #define UIDHASH_MASK (UIDHASH_SZ - 1) #define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) -#define uidhashentry(uid) (uidhash_table + __uidhashfn((__kuid_val(uid)))) +#define uidhashentry(ns, uid) ((ns)->uidhash_table + __uidhashfn((__kuid_val(uid)))) static struct kmem_cache *uid_cachep; -struct hlist_head uidhash_table[UIDHASH_SZ]; /* * The uidhash_lock is mostly taken from process context, but it is @@ -155,9 +153,10 @@ struct user_struct *find_user(kuid_t uid) { struct user_struct *ret; unsigned long flags; + struct user_namespace *ns = current_user_ns(); spin_lock_irqsave(&uidhash_lock, flags); - ret = uid_hash_find(uid, uidhashentry(uid)); + ret = uid_hash_find(uid, uidhashentry(ns, uid)); spin_unlock_irqrestore(&uidhash_lock, flags); return ret; } @@ -173,9 +172,9 @@ void free_uid(struct user_struct *up) free_user(up, flags); } -struct user_struct *alloc_uid(kuid_t uid) +struct user_struct *alloc_uid_ns(struct user_namespace *ns, kuid_t uid) { - struct hlist_head *hashent = uidhashentry(uid); + struct hlist_head *hashent = uidhashentry(ns, uid); struct user_struct *up, *new; spin_lock_irq(&uidhash_lock); @@ -215,6 +214,11 @@ struct user_struct *alloc_uid(kuid_t uid) return NULL; } +struct user_struct *alloc_uid(kuid_t uid) +{ + return alloc_uid_ns(current_user_ns(), uid); +} + static int __init uid_cache_init(void) { int n; @@ -223,11 +227,11 @@ static int __init uid_cache_init(void) 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); for(n = 0; n < UIDHASH_SZ; ++n) - INIT_HLIST_HEAD(uidhash_table + n); + INIT_HLIST_HEAD(init_user_ns.uidhash_table + n); /* Insert the root user immediately (init already runs as root) */ spin_lock_irq(&uidhash_lock); - uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID)); + uid_hash_insert(&root_user, uidhashentry(&init_user_ns, GLOBAL_ROOT_UID)); spin_unlock_irq(&uidhash_lock); return 0; diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 243fb390d744..459b88044c62 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -74,6 +74,7 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) int create_user_ns(struct cred *new) { struct user_namespace *ns, *parent_ns = new->user_ns; + struct user_struct *new_user; kuid_t owner = new->euid; kgid_t group = new->egid; struct ucounts *ucounts; @@ -116,6 +117,17 @@ int create_user_ns(struct cred *new) goto fail_free; ns->ns.ops = &userns_operations; + for (i = 0; i < UIDHASH_SZ; ++i) + INIT_HLIST_HEAD(ns->uidhash_table + i); + + ret = -ENOMEM; + new_user = alloc_uid_ns(ns, owner); + if (!new_user) + goto fail_uid; + + free_uid(new->user); + new->user = new_user; + atomic_set(&ns->count, 1); /* Leave the new->user_ns reference with the new user namespace. */ ns->parent = parent_ns; @@ -146,6 +158,7 @@ int create_user_ns(struct cred *new) #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); #endif +fail_uid: ns_free_inum(&ns->ns); fail_free: kmem_cache_free(user_ns_cachep, ns); -- 2.26.2 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel