FAILED: patch "[PATCH] kernel: make groups_sort calling a responsibility group_info" failed to apply to 4.9-stable tree
Subsystems (6)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
bdcf0a423ea1c40bbb40e7ee483b50fc8aa3d758Mon Sep 17 00:00:00 2001
From: Thiago Rafael Becker <[email protected]>
Date: Thu, 14 Dec 2017 15:33:12 -0800
Subject: [PATCH] kernel: make groups_sort calling a responsibility group_info
allocators
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
arch/s390/kernel/compat_linux.c +1 -0
@@ -263,6 +263,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplisreturn retval; } +groups_sort (group_info); retval =set_current_groups (group_info);put_group_info (group_info);
fs/nfsd/auth.c +3 -0
@@ -60,6 +60,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) gi->gid[i] = exp->ex_anon_gid; else gi->gid[i] = rqgi->gid[i]; + +/* Each thread allocates its own gi, no race */ +groups_sort (gi); } }else { gi =get_group_info (rqgi);
include/linux/cred.h +1 -0
@@ -83,6 +83,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 *);/* * The security context of a task
kernel/groups.c +3 -2
@@ -86,11 +86,12 @@ static int gid_cmp(const void *_a, const void *_b)return gid_gt (a, b) -gid_lt (a, b); } -static void groups_sort (struct group_info *group_info) +void groups_sort (struct group_info *group_info) {sort (group_info->gid, group_info->ngroups,sizeof (*group_info->gid), gid_cmp,NULL ); } +EXPORT_SYMBOL (groups_sort);/* a simple bsearch */ int groups_search (const struct group_info *group_info,kgid_t grp)
@@ -122,7 +123,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); -groups_sort (group_info);get_group_info (group_info); new->group_info = group_info; }
@@ -206,6 +206,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)return retval; } +groups_sort (group_info); retval =set_current_groups (group_info);put_group_info (group_info);
kernel/uid16.c +1 -0
@@ -192,6 +192,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)return retval; } +groups_sort (group_info); retval =set_current_groups (group_info);put_group_info (group_info);
net/sunrpc/auth_gss/gss_rpc_xdr.c +1 -0
@@ -231,6 +231,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, goto out_free_groups; creds->cr_group_info->gid[i] = kgid; } +groups_sort (creds->cr_group_info);return 0 ; out_free_groups:
net/sunrpc/auth_gss/svcauth_gss.c +1 -0
@@ -481,6 +481,7 @@ static int rsc_parse(struct cache_detail *cd, goto out; rsci.cred.cr_group_info->gid[i] = kgid; } +groups_sort (rsci.cred.cr_group_info);/* mech name */ len =qword_get (&mesg, buf, mlen);
net/sunrpc/svcauth_unix.c +2 -0
@@ -520,6 +520,7 @@ static int unix_gid_parse(struct cache_detail *cd, ug.gi->gid[i] = kgid; } +groups_sort (ug.gi); ugp =unix_gid_lookup (cd, uid);if (ugp) {struct cache_head *ch;
@@ -819,6 +820,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)kgid_t kgid =make_kgid (&init_user_ns,svc_getnl (argv)); cred->cr_group_info->gid[i] = kgid; } +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 ;
PATCH 1/1 kernel: make groups_sort calling a responsibility group_info allocators
From: Thiago Rafael Becker <[email protected]>
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
--- 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(-)
arch/s390/kernel/compat_linux.c +1 -0
@@ -263,6 +263,7 @@ COMPAT_SYSCALL_DEFINE2(s390_setgroups16, int, gidsetsize, u16 __user *, grouplisreturn retval; } +groups_sort (group_info); retval =set_current_groups (group_info);put_group_info (group_info);
fs/nfsd/auth.c +3 -0
@@ -59,6 +59,9 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) gi->gid[i] = exp->ex_anon_gid; else gi->gid[i] = rqgi->gid[i]; + +/* Each thread allocates its own gi, no race */ +groups_sort (gi); } }else { gi =get_group_info (rqgi);
include/linux/cred.h +1 -0
@@ -82,6 +82,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 *);/* * The security context of a task
kernel/groups.c +3 -2
@@ -77,7 +77,7 @@ static int groups_from_user(struct group_info *group_info, }/* 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;
@@ -103,6 +103,7 @@ static void groups_sort(struct group_info *group_info) stride /=3 ; } } +EXPORT_SYMBOL (groups_sort);/* a simple bsearch */ int groups_search (const struct group_info *group_info,kgid_t grp)
@@ -134,7 +135,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); -groups_sort (group_info);get_group_info (group_info); new->group_info = group_info; }
@@ -218,6 +218,7 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)return retval; } +groups_sort (group_info); retval =set_current_groups (group_info);put_group_info (group_info);
kernel/uid16.c +1 -0
@@ -190,6 +190,7 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)return retval; } +groups_sort (group_info); retval =set_current_groups (group_info);put_group_info (group_info);
net/sunrpc/auth_gss/gss_rpc_xdr.c +1 -0
@@ -231,6 +231,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr, goto out_free_groups; creds->cr_group_info->gid[i] = kgid; } +groups_sort (creds->cr_group_info);return 0 ; out_free_groups:
net/sunrpc/auth_gss/svcauth_gss.c +1 -0
@@ -481,6 +481,7 @@ static int rsc_parse(struct cache_detail *cd, goto out; rsci.cred.cr_group_info->gid[i] = kgid; } +groups_sort (rsci.cred.cr_group_info);/* mech name */ len =qword_get (&mesg, buf, mlen);
net/sunrpc/svcauth_unix.c +2 -0
@@ -520,6 +520,7 @@ static int unix_gid_parse(struct cache_detail *cd, ug.gi->gid[i] = kgid; } +groups_sort (ug.gi); ugp =unix_gid_lookup (cd, uid);if (ugp) {struct cache_head *ch;
@@ -819,6 +820,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)kgid_t kgid =make_kgid (&init_user_ns,svc_getnl (argv)); cred->cr_group_info->gid[i] = kgid; } +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 ;
Signature · 1 line
2.14.0.rc0.dirty