[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <lsq.1519831221.622436378@decadent.org.uk>
Date: Wed, 28 Feb 2018 15:20:21 +0000
From: Ben Hutchings <ben@...adent.org.uk>
To: linux-kernel@...r.kernel.org, stable@...r.kernel.org
CC: akpm@...ux-foundation.org, "Al Viro" <viro@...iv.linux.org.uk>,
"Thiago Rafael Becker" <thiago.becker@...il.com>,
"Linus Torvalds" <torvalds@...ux-foundation.org>,
"J. Bruce Fields" <bfields@...ldses.org>,
"NeilBrown" <neilb@...e.com>,
"Matthew Wilcox" <mawilcox@...rosoft.com>,
"Martin Schwidefsky" <schwidefsky@...ibm.com>
Subject: [PATCH 3.2 046/140] kernel: make groups_sort calling a
responsibility group_info allocators
3.2.100-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Thiago Rafael Becker <thiago.becker@...il.com>
commit bdcf0a423ea1c40bbb40e7ee483b50fc8aa3d758 upstream.
In testing, we found that nfsd threads may call set_groups in parallel
for the same entry cached in auth.unix.gid, racing in the call of
groups_sort, corrupting the groups for that entry and leading to
permission denials for the client.
This patch:
- Make groups_sort globally visible.
- Move the call to groups_sort to the modifiers of group_info
- Remove the call to groups_sort from set_groups
Link: http://lkml.kernel.org/r/20171211151420.18655-1-thiago.becker@gmail.com
Signed-off-by: Thiago Rafael Becker <thiago.becker@...il.com>
Reviewed-by: Matthew Wilcox <mawilcox@...rosoft.com>
Reviewed-by: NeilBrown <neilb@...e.com>
Acked-by: "J. Bruce Fields" <bfields@...ldses.org>
Cc: Al Viro <viro@...iv.linux.org.uk>
Cc: Martin Schwidefsky <schwidefsky@...ibm.com>
Signed-off-by: Andrew Morton <akpm@...ux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@...ux-foundation.org>
[bwh: Backported to 3.2:
- Drop change in gss_rpc_xdr.c
- Adjust context]
Signed-off-by: Ben Hutchings <ben@...adent.org.uk>
---
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -242,6 +242,7 @@ asmlinkage long sys32_setgroups16(int gi
return retval;
}
+ groups_sort(group_info);
retval = set_current_groups(group_info);
put_group_info(group_info);
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -60,6 +60,9 @@ int nfsd_setuser(struct svc_rqst *rqstp,
GROUP_AT(gi, i) = exp->ex_anon_gid;
else
GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
+
+ /* Each thread allocates its own gi, no race */
+ groups_sort(gi);
}
} else {
gi = get_group_info(rqgi);
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -67,6 +67,7 @@ extern void groups_free(struct group_inf
extern int set_current_groups(struct group_info *);
extern int set_groups(struct cred *, struct group_info *);
extern int groups_search(const struct group_info *, gid_t);
+extern void groups_sort(struct group_info *);
/* access the groups "array" with this macro */
#define GROUP_AT(gi, i) \
--- a/kernel/groups.c
+++ b/kernel/groups.c
@@ -103,7 +103,7 @@ static int groups_from_user(struct group
}
/* a simple Shell sort */
-static void groups_sort(struct group_info *group_info)
+void groups_sort(struct group_info *group_info)
{
int base, max, stride;
int gidsetsize = group_info->ngroups;
@@ -130,6 +130,7 @@ static void groups_sort(struct group_inf
stride /= 3;
}
}
+EXPORT_SYMBOL(groups_sort);
/* a simple bsearch */
int groups_search(const struct group_info *group_info, gid_t grp)
@@ -164,7 +165,6 @@ int groups_search(const struct group_inf
int set_groups(struct cred *new, struct group_info *group_info)
{
put_group_info(new->group_info);
- groups_sort(group_info);
get_group_info(group_info);
new->group_info = group_info;
return 0;
@@ -247,6 +247,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsi
return retval;
}
+ groups_sort(group_info);
retval = set_current_groups(group_info);
put_group_info(group_info);
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -203,6 +203,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidset
return retval;
}
+ groups_sort(group_info);
retval = set_current_groups(group_info);
put_group_info(group_info);
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -477,6 +477,7 @@ static int rsc_parse(struct cache_detail
goto out;
GROUP_AT(rsci.cred.cr_group_info, i) = gid;
}
+ groups_sort(rsci.cred.cr_group_info);
/* mech name */
len = qword_get(&mesg, buf, mlen);
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -539,6 +539,7 @@ static int unix_gid_parse(struct cache_d
GROUP_AT(ug.gi, i) = gid;
}
+ groups_sort(ug.gi);
ugp = unix_gid_lookup(uid);
if (ugp) {
struct cache_head *ch;
@@ -806,6 +807,7 @@ svcauth_unix_accept(struct svc_rqst *rqs
return SVC_CLOSE;
for (i = 0; i < slen; i++)
GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
+ groups_sort(cred->cr_group_info);
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf;
return SVC_DENIED;
Powered by blists - more mailing lists