91 lines
2.9 KiB
Diff
91 lines
2.9 KiB
Diff
From: "Eric W. Biederman" <ebiederm@xmission.com>
|
|
Date: Fri, 5 Dec 2014 17:19:27 -0600
|
|
Subject: [PATCH] groups: Consolidate the setgroups permission checks
|
|
|
|
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 | 2 +-
|
|
include/linux/cred.h | 1 +
|
|
kernel/groups.c | 9 ++++++++-
|
|
kernel/uid16.c | 2 +-
|
|
4 files changed, 11 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
|
|
index ca38139423ae..437e61159279 100644
|
|
--- a/arch/s390/kernel/compat_linux.c
|
|
+++ b/arch/s390/kernel/compat_linux.c
|
|
@@ -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;
|
|
diff --git a/include/linux/cred.h b/include/linux/cred.h
|
|
index b2d0820837c4..2fb2ca2127ed 100644
|
|
--- a/include/linux/cred.h
|
|
+++ b/include/linux/cred.h
|
|
@@ -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) \
|
|
diff --git a/kernel/groups.c b/kernel/groups.c
|
|
index 451698f86cfa..02d8a251c476 100644
|
|
--- a/kernel/groups.c
|
|
+++ b/kernel/groups.c
|
|
@@ -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;
|
|
diff --git a/kernel/uid16.c b/kernel/uid16.c
|
|
index 602e5bbbceff..d58cc4d8f0d1 100644
|
|
--- a/kernel/uid16.c
|
|
+++ b/kernel/uid16.c
|
|
@@ -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;
|
|
--
|
|
2.1.0
|
|
|