From: Tim Hockin Avoid performing a syscall from inside nfsd. --- 25-akpm/fs/nfsd/auth.c | 43 ++++++++++++++++++++++++++------------ 25-akpm/include/linux/nfsd/auth.h | 2 - 25-akpm/kernel/sys.c | 6 +++++ 3 files changed, 37 insertions(+), 14 deletions(-) diff -puN fs/nfsd/auth.c~increase-NGROUPS-nfsd-cleanup fs/nfsd/auth.c --- 25/fs/nfsd/auth.c~increase-NGROUPS-nfsd-cleanup Thu Feb 5 16:04:50 2004 +++ 25-akpm/fs/nfsd/auth.c Thu Feb 5 16:04:52 2004 @@ -10,15 +10,27 @@ #include #include -extern asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist); - #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) -void -nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) + +int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) { struct svc_cred *cred = &rqstp->rq_cred; - int i; - gid_t groups[SVC_CRED_NGROUPS]; + struct group_info *group_info; + int ngroups; + int i; + int ret; + + ngroups = 0; + if (!(exp->ex_flags & NFSEXP_ALLSQUASH)) { + for (i = 0; i < SVC_CRED_NGROUPS; i++) { + if (cred->cr_groups[i] == (gid_t)NOGROUP) + break; + ngroups++; + } + } + group_info = groups_alloc(ngroups); + if (group_info == NULL) + return -ENOMEM; if (exp->ex_flags & NFSEXP_ALLSQUASH) { cred->cr_uid = exp->ex_anon_uid; @@ -42,19 +54,24 @@ nfsd_setuser(struct svc_rqst *rqstp, str current->fsgid = cred->cr_gid; else current->fsgid = exp->ex_anon_gid; + for (i = 0; i < SVC_CRED_NGROUPS; i++) { gid_t group = cred->cr_groups[i]; if (group == (gid_t) NOGROUP) break; - groups[i] = group; + GROUP_AT(group_info, i) = group; } - sys_setgroups(i, groups); - if ((cred->cr_uid)) { - cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; + ret = set_current_groups(group_info); + if (ret == 0) { + if ((cred->cr_uid)) { + cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; + } else { + cap_t(current->cap_effective) |= (CAP_NFSD_MASK & + current->cap_permitted); + } } else { - cap_t(current->cap_effective) |= (CAP_NFSD_MASK & - current->cap_permitted); + put_group_info(group_info); } - + return ret; } diff -puN kernel/sys.c~increase-NGROUPS-nfsd-cleanup kernel/sys.c --- 25/kernel/sys.c~increase-NGROUPS-nfsd-cleanup Thu Feb 5 16:04:50 2004 +++ 25-akpm/kernel/sys.c Thu Feb 5 16:04:52 2004 @@ -1130,6 +1130,8 @@ out_undo_partial_alloc: return NULL; } +EXPORT_SYMBOL(groups_alloc); + void groups_free(struct group_info *group_info) { if (group_info->blocks[0] != group_info->small_block) { @@ -1140,6 +1142,8 @@ void groups_free(struct group_info *grou kfree(group_info); } +EXPORT_SYMBOL(groups_free); + /* export the group_info to a user-space array */ static int groups_to_user(gid_t __user *grouplist, struct group_info *group_info) @@ -1250,6 +1254,8 @@ int set_current_groups(struct group_info return 0; } +EXPORT_SYMBOL(set_current_groups); + asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist) { int i = 0; diff -puN include/linux/nfsd/auth.h~increase-NGROUPS-nfsd-cleanup include/linux/nfsd/auth.h --- 25/include/linux/nfsd/auth.h~increase-NGROUPS-nfsd-cleanup Thu Feb 5 16:04:50 2004 +++ 25-akpm/include/linux/nfsd/auth.h Thu Feb 5 16:04:50 2004 @@ -21,7 +21,7 @@ * Set the current process's fsuid/fsgid etc to those of the NFS * client user */ -void nfsd_setuser(struct svc_rqst *, struct svc_export *); +int nfsd_setuser(struct svc_rqst *, struct svc_export *); #endif /* __KERNEL__ */ #endif /* LINUX_NFSD_AUTH_H */ _