groups: Consolidate the setgroups permission checks
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 5 Dec 2014 23:19:27 +0000 (17:19 -0600)
committerEric W. Biederman <ebiederm@xmission.com>
Fri, 5 Dec 2014 23:19:27 +0000 (17:19 -0600)
Today there are 3 instances of setgroups and due to an oversight their
permission checking has diverged.  Add a common function so that
they may all share the same permission checking code.

This corrects the current oversight in the current permission checks
and adds a helper to avoid this in the future.

A user namespace security fix will update this new helper, shortly.

Cc: stable@vger.kernel.org
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
arch/s390/kernel/compat_linux.c
include/linux/cred.h
kernel/groups.c
kernel/uid16.c

index ca38139423ae7f22e3a4d5e33d4990d9f4bc5daa..437e611592790b0ed725998d08281be420fcf954 100644 (file)
@@ -249,7 +249,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplis
        struct group_info *group_info;
        int retval;
 
-       if (!capable(CAP_SETGID))
+       if (!may_setgroups())
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;
index b2d0820837c4259915c42208e696b09bf56c365d..2fb2ca2127ed0f031fb9639d41f56b7d3fdee88b 100644 (file)
@@ -68,6 +68,7 @@ extern void groups_free(struct group_info *);
 extern int set_current_groups(struct group_info *);
 extern void set_groups(struct cred *, struct group_info *);
 extern int groups_search(const struct group_info *, kgid_t);
+extern bool may_setgroups(void);
 
 /* access the groups "array" with this macro */
 #define GROUP_AT(gi, i) \
index 451698f86cfadae2eef8805df0795310b3f1d797..02d8a251c47656593690ceabd36ea42f42cc2cdb 100644 (file)
@@ -213,6 +213,13 @@ out:
        return i;
 }
 
+bool may_setgroups(void)
+{
+       struct user_namespace *user_ns = current_user_ns();
+
+       return ns_capable(user_ns, CAP_SETGID);
+}
+
 /*
  *     SMP: Our groups are copy-on-write. We can set them safely
  *     without another task interfering.
@@ -223,7 +230,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
        struct group_info *group_info;
        int retval;
 
-       if (!ns_capable(current_user_ns(), CAP_SETGID))
+       if (!may_setgroups())
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;
index 602e5bbbceff51ef47d4a22d2e3a51e34a88cfd5..d58cc4d8f0d1fa95c7ec0120cb408a9b4ad859e5 100644 (file)
@@ -176,7 +176,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
        struct group_info *group_info;
        int retval;
 
-       if (!ns_capable(current_user_ns(), CAP_SETGID))
+       if (!may_setgroups())
                return -EPERM;
        if ((unsigned)gidsetsize > NGROUPS_MAX)
                return -EINVAL;