Revert "Add a reference to ucounts for each cred"
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 3 Sep 2021 14:06:50 +0000 (16:06 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Sep 2021 06:49:00 +0000 (08:49 +0200)
This reverts commit b2c4d9a33cc2dec7466f97eba2c4dd571ad798a5 which is
commit 905ae01c4ae2ae3df05bb141801b1db4b7d83c61 upstream.

This commit should not have been applied to the 5.10.y stable tree, so
revert it.

Reported-by: "Eric W. Biederman" <ebiederm@xmission.com>
Link: https://lore.kernel.org/r/87v93k4bl6.fsf@disp2133
Cc: Alexey Gladkov <legion@kernel.org>
Cc: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/exec.c
include/linux/cred.h
include/linux/user_namespace.h
kernel/cred.c
kernel/fork.c
kernel/sys.c
kernel/ucount.c
kernel/user_namespace.c

index c7a4ef8df3058cf584f768b37d701e9b47f022f7..ca89e0e3ef10f19ee0ba7243c52fa7ff130900cf 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1347,10 +1347,6 @@ int begin_new_exec(struct linux_binprm * bprm)
        WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);
        flush_signal_handlers(me, 0);
 
-       retval = set_cred_ucounts(bprm->cred);
-       if (retval < 0)
-               goto out_unlock;
-
        /*
         * install the new credentials for this executable
         */
index ad160e5fe5c6466defd4faa4de10308faae7b119..18639c069263fbe79dfd5a36163c656dca5da220 100644 (file)
@@ -144,7 +144,6 @@ struct cred {
 #endif
        struct user_struct *user;       /* real user ID subscription */
        struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
-       struct ucounts *ucounts;
        struct group_info *group_info;  /* supplementary groups for euid/fsgid */
        /* RCU deletion */
        union {
@@ -171,7 +170,6 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
 extern int set_create_files_as(struct cred *, struct inode *);
 extern int cred_fscmp(const struct cred *, const struct cred *);
 extern void __init cred_init(void);
-extern int set_cred_ucounts(struct cred *);
 
 /*
  * check for validity of credentials
index e1bd560da1cd4c5242d59c30527102faadda8069..7616c7bf4b241069f4cf31e994f04b872524e566 100644 (file)
@@ -101,15 +101,11 @@ struct ucounts {
 };
 
 extern struct user_namespace init_user_ns;
-extern struct ucounts init_ucounts;
 
 bool setup_userns_sysctls(struct user_namespace *ns);
 void retire_userns_sysctls(struct user_namespace *ns);
 struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
 void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
-struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
-struct ucounts *get_ucounts(struct ucounts *ucounts);
-void put_ucounts(struct ucounts *ucounts);
 
 #ifdef CONFIG_USER_NS
 
index 58a8a9e24347d4202a96a412e17ce2288db5c273..421b1149c6516004221159824dc6c18770db64e6 100644 (file)
@@ -60,7 +60,6 @@ struct cred init_cred = {
        .user                   = INIT_USER,
        .user_ns                = &init_user_ns,
        .group_info             = &init_groups,
-       .ucounts                = &init_ucounts,
 };
 
 static inline void set_cred_subscribers(struct cred *cred, int n)
@@ -120,8 +119,6 @@ static void put_cred_rcu(struct rcu_head *rcu)
        if (cred->group_info)
                put_group_info(cred->group_info);
        free_uid(cred->user);
-       if (cred->ucounts)
-               put_ucounts(cred->ucounts);
        put_user_ns(cred->user_ns);
        kmem_cache_free(cred_jar, cred);
 }
@@ -225,7 +222,6 @@ struct cred *cred_alloc_blank(void)
 #ifdef CONFIG_DEBUG_CREDENTIALS
        new->magic = CRED_MAGIC;
 #endif
-       new->ucounts = get_ucounts(&init_ucounts);
 
        if (security_cred_alloc_blank(new, GFP_KERNEL_ACCOUNT) < 0)
                goto error;
@@ -288,11 +284,6 @@ struct cred *prepare_creds(void)
 
        if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
                goto error;
-
-       new->ucounts = get_ucounts(new->ucounts);
-       if (!new->ucounts)
-               goto error;
-
        validate_creds(new);
        return new;
 
@@ -372,8 +363,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
                ret = create_user_ns(new);
                if (ret < 0)
                        goto error_put;
-               if (set_cred_ucounts(new) < 0)
-                       goto error_put;
        }
 
 #ifdef CONFIG_KEYS
@@ -664,31 +653,6 @@ int cred_fscmp(const struct cred *a, const struct cred *b)
 }
 EXPORT_SYMBOL(cred_fscmp);
 
-int set_cred_ucounts(struct cred *new)
-{
-       struct task_struct *task = current;
-       const struct cred *old = task->real_cred;
-       struct ucounts *old_ucounts = new->ucounts;
-
-       if (new->user == old->user && new->user_ns == old->user_ns)
-               return 0;
-
-       /*
-        * This optimization is needed because alloc_ucounts() uses locks
-        * for table lookups.
-        */
-       if (old_ucounts && old_ucounts->ns == new->user_ns && uid_eq(old_ucounts->uid, new->euid))
-               return 0;
-
-       if (!(new->ucounts = alloc_ucounts(new->user_ns, new->euid)))
-               return -EAGAIN;
-
-       if (old_ucounts)
-               put_ucounts(old_ucounts);
-
-       return 0;
-}
-
 /*
  * initialise the credentials stuff
  */
@@ -755,10 +719,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
        if (security_prepare_creds(new, old, GFP_KERNEL_ACCOUNT) < 0)
                goto error;
 
-       new->ucounts = get_ucounts(new->ucounts);
-       if (!new->ucounts)
-               goto error;
-
        put_cred(old);
        validate_creds(new);
        return new;
index 096945ef49ad75dee51951832270f07a1dbf10ce..9705439439fe37abc001cc3d040fab6fb0f9c79a 100644 (file)
@@ -2960,12 +2960,6 @@ int ksys_unshare(unsigned long unshare_flags)
        if (err)
                goto bad_unshare_cleanup_cred;
 
-       if (new_cred) {
-               err = set_cred_ucounts(new_cred);
-               if (err)
-                       goto bad_unshare_cleanup_cred;
-       }
-
        if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
                if (do_sysvsem) {
                        /*
index 0670e824e0197ae70f6d92b681f5448af60864ee..a730c03ee607cc5941628ed6fc1800f512d41467 100644 (file)
@@ -552,10 +552,6 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
        if (retval < 0)
                goto error;
 
-       retval = set_cred_ucounts(new);
-       if (retval < 0)
-               goto error;
-
        return commit_creds(new);
 
 error:
@@ -614,10 +610,6 @@ long __sys_setuid(uid_t uid)
        if (retval < 0)
                goto error;
 
-       retval = set_cred_ucounts(new);
-       if (retval < 0)
-               goto error;
-
        return commit_creds(new);
 
 error:
@@ -693,10 +685,6 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        if (retval < 0)
                goto error;
 
-       retval = set_cred_ucounts(new);
-       if (retval < 0)
-               goto error;
-
        return commit_creds(new);
 
 error:
index 9894795043c4229d19d583241dd9b51c0a14efb9..11b1596e2542a5e28061cb31201e2a89bf66e936 100644 (file)
@@ -8,12 +8,6 @@
 #include <linux/kmemleak.h>
 #include <linux/user_namespace.h>
 
-struct ucounts init_ucounts = {
-       .ns    = &init_user_ns,
-       .uid   = GLOBAL_ROOT_UID,
-       .count = 1,
-};
-
 #define UCOUNTS_HASHTABLE_BITS 10
 static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
 static DEFINE_SPINLOCK(ucounts_lock);
@@ -131,15 +125,7 @@ static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struc
        return NULL;
 }
 
-static void hlist_add_ucounts(struct ucounts *ucounts)
-{
-       struct hlist_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid);
-       spin_lock_irq(&ucounts_lock);
-       hlist_add_head(&ucounts->node, hashent);
-       spin_unlock_irq(&ucounts_lock);
-}
-
-struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
+static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid)
 {
        struct hlist_head *hashent = ucounts_hashentry(ns, uid);
        struct ucounts *ucounts, *new;
@@ -174,26 +160,7 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
        return ucounts;
 }
 
-struct ucounts *get_ucounts(struct ucounts *ucounts)
-{
-       unsigned long flags;
-
-       if (!ucounts)
-               return NULL;
-
-       spin_lock_irqsave(&ucounts_lock, flags);
-       if (ucounts->count == INT_MAX) {
-               WARN_ONCE(1, "ucounts: counter has reached its maximum value");
-               ucounts = NULL;
-       } else {
-               ucounts->count += 1;
-       }
-       spin_unlock_irqrestore(&ucounts_lock, flags);
-
-       return ucounts;
-}
-
-void put_ucounts(struct ucounts *ucounts)
+static void put_ucounts(struct ucounts *ucounts)
 {
        unsigned long flags;
 
@@ -227,7 +194,7 @@ struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid,
 {
        struct ucounts *ucounts, *iter, *bad;
        struct user_namespace *tns;
-       ucounts = alloc_ucounts(ns, uid);
+       ucounts = get_ucounts(ns, uid);
        for (iter = ucounts; iter; iter = tns->ucounts) {
                int max;
                tns = iter->ns;
@@ -270,7 +237,6 @@ static __init int user_namespace_sysctl_init(void)
        BUG_ON(!user_header);
        BUG_ON(!setup_userns_sysctls(&init_user_ns));
 #endif
-       hlist_add_ucounts(&init_ucounts);
        return 0;
 }
 subsys_initcall(user_namespace_sysctl_init);
index 8206a13c81ebcdcd21d9aa0467e86293185da4bf..ce396ea4de60891b4040da0c04e0facf96b81332 100644 (file)
@@ -1340,9 +1340,6 @@ static int userns_install(struct nsset *nsset, struct ns_common *ns)
        put_user_ns(cred->user_ns);
        set_cred_user_ns(cred, get_user_ns(user_ns));
 
-       if (set_cred_ucounts(cred) < 0)
-               return -EINVAL;
-
        return 0;
 }