ucounts: Proper error handling in set_cred_ucounts
authorEric W. Biederman <ebiederm@xmission.com>
Sat, 16 Oct 2021 17:47:51 +0000 (12:47 -0500)
committerEric W. Biederman <ebiederm@xmission.com>
Tue, 19 Oct 2021 16:04:25 +0000 (11:04 -0500)
Instead of leaking the ucounts in new if alloc_ucounts fails, store
the result of alloc_ucounts into a temporary variable, which is later
assigned to new->ucounts.

Cc: stable@vger.kernel.org
Fixes: 905ae01c4ae2 ("Add a reference to ucounts for each cred")
Link: https://lkml.kernel.org/r/87pms2s0v8.fsf_-_@disp2133
Tested-by: Yu Zhao <yuzhao@google.com>
Reviewed-by: Alexey Gladkov <legion@kernel.org>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
kernel/cred.c

index 3d163bf..16c05df 100644 (file)
@@ -669,7 +669,7 @@ 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;
+       struct ucounts *new_ucounts, *old_ucounts = new->ucounts;
 
        if (new->user == old->user && new->user_ns == old->user_ns)
                return 0;
@@ -681,9 +681,10 @@ int set_cred_ucounts(struct cred *new)
        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)))
+       if (!(new_ucounts = alloc_ucounts(new->user_ns, new->euid)))
                return -EAGAIN;
 
+       new->ucounts = new_ucounts;
        if (old_ucounts)
                put_ucounts(old_ucounts);