The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git after ark-5.14 ------> commit 90e4f99d0fa705913b5b14715a60f85bafd1c394 Author: Andrey Ryabinin <ryabinin....@gmail.com> Date: Fri Oct 1 19:38:50 2021 +0300
userns: associate user_struct with the user_namespace 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> (cherry-picked from vz8 commit c6c5b5eeadb3 ("userns: associate user_struct with the user_namespace")) Signed-off-by: Nikita Yushchenko <nikita.yushche...@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 2462f7d07695..08cab810d441 100644 --- a/include/linux/sched/user.h +++ b/include/linux/sched/user.h @@ -41,6 +41,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 eb70cabe6e7f..ebd15484cf0b 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -14,6 +14,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; @@ -67,6 +70,7 @@ struct user_namespace { struct uid_gid_map uid_map; struct uid_gid_map gid_map; struct uid_gid_map projid_map; + 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 c82399c1618a..ca0f7c78a045 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -9,6 +9,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> @@ -75,14 +76,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; -static struct hlist_head uidhash_table[UIDHASH_SZ]; /* * The uidhash_lock is mostly taken from process context, but it is @@ -151,9 +149,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; } @@ -169,9 +168,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); @@ -206,6 +205,11 @@ struct user_struct *alloc_uid(kuid_t uid) return up; } +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; @@ -214,11 +218,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 6b2e3ca7ee99..901f4870b4a1 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -69,6 +69,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; @@ -112,6 +113,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; + refcount_set(&ns->ns.count, 1); /* Leave the new->user_ns reference with the new user namespace. */ ns->parent = parent_ns; @@ -147,6 +159,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); _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel