[Devel] [PATCH vz9 23/23] userns: associate user_struct with the user_namespace
Nikita Yushchenko
nikita.yushchenko at virtuozzo.com
Fri Oct 1 18:53:31 MSK 2021
From: Andrey Ryabinin <aryabinin at virtuozzo.com>
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 <aryabinin at virtuozzo.com>
(cherry-picked from vz8 commit c6c5b5eeadb3 ("userns: associate
user_struct with the user_namespace"))
Signed-off-by: Nikita Yushchenko <nikita.yushchenko at 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);
--
2.30.2
More information about the Devel
mailing list