From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx2.suse.de ([195.135.220.15]:36249 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751134AbeACWVS (ORCPT ); Wed, 3 Jan 2018 17:21:18 -0500 From: NeilBrown To: gregkh@linuxfoundation.org, thiago.becker@gmail.com, akpm@linux-foundation.org, bfields@fieldses.org, mawilcox@microsoft.com, schwidefsky@de.ibm.com, stable@vger.kernel.org, torvalds@linux-foundation.org, viro@zeniv.linux.org.uk Date: Thu, 04 Jan 2018 09:21:05 +1100 Cc: stable@vger.kernel.org Subject: [PATCH - 4.4-stable backport] kernel: make groups_sort calling a responsibility group_info allocators In-Reply-To: <1513596999178204@kroah.com> References: <1513596999178204@kroah.com> Message-ID: <87incieg8e.fsf@notabene.neil.brown.name> MIME-Version: 1.0 Content-Type: multipart/signed; boundary="=-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" Sender: stable-owner@vger.kernel.org List-ID: --=-=-= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable From: Thiago Rafael Becker 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.c= om Signed-off-by: Thiago Rafael Becker Reviewed-by: Matthew Wilcox Reviewed-by: NeilBrown Acked-by: "J. Bruce Fields" Cc: Al Viro Cc: Martin Schwidefsky Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds =2D-- arch/s390/kernel/compat_linux.c | 1 + fs/nfsd/auth.c | 3 +++ include/linux/cred.h | 1 + kernel/groups.c | 5 +++-- kernel/uid16.c | 1 + net/sunrpc/auth_gss/gss_rpc_xdr.c | 1 + net/sunrpc/auth_gss/svcauth_gss.c | 1 + net/sunrpc/svcauth_unix.c | 2 ++ 8 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linu= x.c index 437e61159279..0176ebc97bfd 100644 =2D-- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -263,6 +263,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsiz= e, u16 __user *, grouplis return retval; } =20 + groups_sort(group_info); retval =3D set_current_groups(group_info); put_group_info(group_info); =20 diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 9d46a0bdd9f9..a260060042ad 100644 =2D-- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -59,6 +59,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_expor= t *exp) GROUP_AT(gi, i) =3D exp->ex_anon_gid; else GROUP_AT(gi, i) =3D GROUP_AT(rqgi, i); + + /* Each thread allocates its own gi, no race */ + groups_sort(gi); } } else { gi =3D get_group_info(rqgi); diff --git a/include/linux/cred.h b/include/linux/cred.h index 257db64562e5..9e120c92551b 100644 =2D-- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -87,6 +87,7 @@ 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); +extern void groups_sort(struct group_info *); =20 /* access the groups "array" with this macro */ #define GROUP_AT(gi, i) \ diff --git a/kernel/groups.c b/kernel/groups.c index 74d431d25251..5ea9847f172f 100644 =2D-- a/kernel/groups.c +++ b/kernel/groups.c @@ -101,7 +101,7 @@ static int groups_from_user(struct group_info *group_in= fo, } =20 /* a simple Shell sort */ =2Dstatic void groups_sort(struct group_info *group_info) +void groups_sort(struct group_info *group_info) { int base, max, stride; int gidsetsize =3D group_info->ngroups; @@ -128,6 +128,7 @@ static void groups_sort(struct group_info *group_info) stride /=3D 3; } } +EXPORT_SYMBOL(groups_sort); =20 /* a simple bsearch */ int groups_search(const struct group_info *group_info, kgid_t grp) @@ -159,7 +160,6 @@ int groups_search(const struct group_info *group_info, = kgid_t grp) void set_groups(struct cred *new, struct group_info *group_info) { put_group_info(new->group_info); =2D groups_sort(group_info); get_group_info(group_info); new->group_info =3D group_info; } @@ -243,6 +243,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __use= r *, grouplist) return retval; } =20 + groups_sort(group_info); retval =3D set_current_groups(group_info); put_group_info(group_info); =20 diff --git a/kernel/uid16.c b/kernel/uid16.c index d58cc4d8f0d1..651aaa5221ec 100644 =2D-- a/kernel/uid16.c +++ b/kernel/uid16.c @@ -190,6 +190,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t= __user *, grouplist) return retval; } =20 + groups_sort(group_info); retval =3D set_current_groups(group_info); put_group_info(group_info); =20 diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rp= c_xdr.c index 2410d557ae39..89731c9023f0 100644 =2D-- a/net/sunrpc/auth_gss/gss_rpc_xdr.c +++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c @@ -231,6 +231,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, goto out_free_groups; GROUP_AT(creds->cr_group_info, i) =3D kgid; } + groups_sort(creds->cr_group_info); =20 return 0; out_free_groups: diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcaut= h_gss.c index 033fec307528..036bbf2b44c1 100644 =2D-- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c @@ -481,6 +481,7 @@ static int rsc_parse(struct cache_detail *cd, goto out; GROUP_AT(rsci.cred.cr_group_info, i) =3D kgid; } + groups_sort(rsci.cred.cr_group_info); =20 /* mech name */ len =3D qword_get(&mesg, buf, mlen); diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index 621ca7b4a155..98db1715cb17 100644 =2D-- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -520,6 +520,7 @@ static int unix_gid_parse(struct cache_detail *cd, GROUP_AT(ug.gi, i) =3D kgid; } =20 + groups_sort(ug.gi); ugp =3D unix_gid_lookup(cd, uid); if (ugp) { struct cache_head *ch; @@ -827,6 +828,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *aut= hp) kgid_t kgid =3D make_kgid(&init_user_ns, svc_getnl(argv)); GROUP_AT(cred->cr_group_info, i) =3D kgid; } + groups_sort(cred->cr_group_info); if (svc_getu32(argv) !=3D htonl(RPC_AUTH_NULL) || svc_getu32(argv) !=3D 0= ) { *authp =3D rpc_autherr_badverf; return SVC_DENIED; =2D-=20 2.14.0.rc0.dirty --=-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEG8Yp69OQ2HB7X0l6Oeye3VZigbkFAlpNV1EACgkQOeye3VZi gbkNLRAAsC4Ja9bZU92Qr2HN6CrukFX/k4ZlnEi7GnnD0UeoLx4NA8mFgiLNvpkM Tdv3OIH7IvUI3ZlgwOVJBhWnLf2lndBtc80ZUvsw1PNtqG0L9dkd1vtS5fMvl0vA tdel587e2t/jphDqWzaWzRWSk38wC/Jj+wZTcOKzVY//b58t852kcsyCJQJ4N8FE bGCVqRUMK6ZWT2vtEcAnpDs++QfteugKUvlgttBECWGUKHJ8voRApo367INDKDQg eMnqQ1KwluYR2YmRWxugNMOWzrt7jVW3Zx5uN+F0XDkJJ86KAgz8U34PgSdMzkBn o1sNaAt3KcAcrcliqyj9kyetoAnM1At/bzOzXiinV1SqDKbGYCf0ZUXZ8mIH0JnX ysEW/znEOhbwCUlEh5JCrSJUnWdmWtIZ/89LCmwPk45rL8wc3n3jt0Zhy23eNjhR XbDbS5Xb8FX9eFtUbm4KWWxncQfRJmtZB8brg7pRAogL4v6B4tQyzvd3TdzYd8XY WV9gwo7cjHZgqNbc9piluXRBkD33MoW1kkiRc33H+xHatydepjveJwAPOlr2hq8h GFdlL89K7EM0Ofl5c6XA/U9WDeY7+k8TM9BmAVlOetAFW0AyaajZ7OEusycxkUBO Bq7kvtT0RpNyQ8iqcKqksCJ3rHdRGuYcUcbMXYXRhfL+Y7ven04= =mS73 -----END PGP SIGNATURE----- --=-=-=--