Message ID | 20240701025802.22985-3-neilb@suse.de (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | nfsd: provide simpler interface for LOCALIO access | expand |
On Mon, 2024-07-01 at 12:53 +1000, NeilBrown wrote: > __fh_verify() now takes a 'cred' parameter and never dereferences > rqstp->rq_cred. > > nfsd_permission(), nfsd_setuser() and nfsexp_flags() only never needed "only ever" > the cred out of rqstp, so we now pass in the cred explicitly and not the > rqstp. > > nfsd_originating_port_ok() is NOT passed a cred despite that it uses > one. This function is not useful when rqstp is NULL and a future patch > will address that. > > Signed-off-by: NeilBrown <neilb@suse.de> > --- > fs/nfsd/auth.c | 14 +++++++------- > fs/nfsd/auth.h | 2 +- > fs/nfsd/export.h | 3 ++- > fs/nfsd/nfs4state.c | 3 ++- > fs/nfsd/nfsfh.c | 18 +++++++++++------- > fs/nfsd/nfsproc.c | 9 +++++---- > fs/nfsd/vfs.c | 21 ++++++++++++--------- > fs/nfsd/vfs.h | 2 +- > 8 files changed, 41 insertions(+), 31 deletions(-) > > diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c > index e6beaaf4f170..93e33d1ee891 100644 > --- a/fs/nfsd/auth.c > +++ b/fs/nfsd/auth.c > @@ -5,26 +5,26 @@ > #include "nfsd.h" > #include "auth.h" > > -int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) > +int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp) > { > struct exp_flavor_info *f; > struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; > > for (f = exp->ex_flavors; f < end; f++) { > - if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) > + if (f->pseudoflavor == cred->cr_flavor) > return f->flags; > } > return exp->ex_flags; > > } > > -int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) > +int nfsd_setuser(struct svc_cred *cred, struct svc_export *exp) > { > struct group_info *rqgi; > struct group_info *gi; > struct cred *new; > int i; > - int flags = nfsexp_flags(rqstp, exp); > + int flags = nfsexp_flags(cred, exp); > > /* discard any old override before preparing the new set */ > revert_creds(get_cred(current_real_cred())); > @@ -32,10 +32,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) > if (!new) > return -ENOMEM; > > - new->fsuid = rqstp->rq_cred.cr_uid; > - new->fsgid = rqstp->rq_cred.cr_gid; > + new->fsuid = cred->cr_uid; > + new->fsgid = cred->cr_gid; > > - rqgi = rqstp->rq_cred.cr_group_info; > + rqgi = cred->cr_group_info; > > if (flags & NFSEXP_ALLSQUASH) { > new->fsuid = exp->ex_anon_uid; > diff --git a/fs/nfsd/auth.h b/fs/nfsd/auth.h > index dbd66424f600..fc75c5d90be4 100644 > --- a/fs/nfsd/auth.h > +++ b/fs/nfsd/auth.h > @@ -12,6 +12,6 @@ > * Set the current process's fsuid/fsgid etc to those of the NFS > * client user > */ > -int nfsd_setuser(struct svc_rqst *, struct svc_export *); > +int nfsd_setuser(struct svc_cred *, struct svc_export *); > > #endif /* LINUX_NFSD_AUTH_H */ > diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h > index 1a54d388d58d..2dbd15704a86 100644 > --- a/fs/nfsd/export.h > +++ b/fs/nfsd/export.h > @@ -99,7 +99,8 @@ struct svc_expkey { > #define EX_NOHIDE(exp) ((exp)->ex_flags & NFSEXP_NOHIDE) > #define EX_WGATHER(exp) ((exp)->ex_flags & NFSEXP_GATHERED_WRITES) > > -int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp); > +struct svc_cred; > +int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp); > __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp); > > /* > diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c > index a20c2c9d7d45..eadb7d1a7f13 100644 > --- a/fs/nfsd/nfs4state.c > +++ b/fs/nfsd/nfs4state.c > @@ -6889,7 +6889,8 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, > > nf = nfs4_find_file(s, flags); > if (nf) { > - status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, > + status = nfsd_permission(&rqstp->rq_cred, > + fhp->fh_export, fhp->fh_dentry, > acc | NFSD_MAY_OWNER_OVERRIDE); > if (status) { > nfsd_file_put(nf); > diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c > index e27ed27054ab..760684fa4b50 100644 > --- a/fs/nfsd/nfsfh.c > +++ b/fs/nfsd/nfsfh.c > @@ -100,9 +100,10 @@ static bool nfsd_originating_port_ok(struct svc_rqst *rqstp, int flags) > } > > static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, > + struct svc_cred *cred, > struct svc_export *exp) > { > - int flags = nfsexp_flags(rqstp, exp); > + int flags = nfsexp_flags(cred, exp); > > /* Check if the request originated from a secure port. */ > if (!nfsd_originating_port_ok(rqstp, flags)) { > @@ -113,7 +114,7 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, > } > > /* Set user creds for this exportpoint */ > - return nfserrno(nfsd_setuser(rqstp, exp)); > + return nfserrno(nfsd_setuser(cred, exp)); > } > > static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, > @@ -152,6 +153,7 @@ static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, > * fh_dentry. > */ > static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn, > + struct svc_cred *cred, > struct svc_fh *fhp) > { > struct knfsd_fh *fh = &fhp->fh_handle; > @@ -230,7 +232,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn, > put_cred(override_creds(new)); > put_cred(new); > } else { > - error = nfsd_setuser_and_check_port(rqstp, exp); > + error = nfsd_setuser_and_check_port(rqstp, cred, exp); > if (error) > goto out; > } > @@ -326,7 +328,8 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn, > * fs/nfsd/vfs.h. > */ > static __be32 > -__fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, > +__fh_verify(struct svc_rqst *rqstp, > + struct nfsd_net *nn, struct svc_cred *cred, > struct svc_fh *fhp, umode_t type, int access) > { > struct svc_export *exp = NULL; > @@ -334,7 +337,7 @@ __fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, > __be32 error; > > if (!fhp->fh_dentry) { > - error = nfsd_set_fh_dentry(rqstp, nn, fhp); > + error = nfsd_set_fh_dentry(rqstp, nn, cred, fhp); > if (error) > goto out; > } > @@ -363,7 +366,7 @@ __fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, > if (error) > goto out; > > - error = nfsd_setuser_and_check_port(rqstp, exp); > + error = nfsd_setuser_and_check_port(rqstp, cred, exp); > if (error) > goto out; > > @@ -393,7 +396,7 @@ __fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, > > skip_pseudoflavor_check: > /* Finally, check access permissions. */ > - error = nfsd_permission(rqstp, exp, dentry, access); > + error = nfsd_permission(cred, exp, dentry, access); > out: > trace_nfsd_fh_verify_err(rqstp, fhp, type, access, error); > if (error == nfserr_stale) > @@ -405,6 +408,7 @@ __be32 > fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) > { > return __fh_verify(rqstp, net_generic(SVC_NET(rqstp), nfsd_net_id), > + &rqstp->rq_cred, > fhp, type, access); > } > > diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c > index 36370b957b63..97aab34593ef 100644 > --- a/fs/nfsd/nfsproc.c > +++ b/fs/nfsd/nfsproc.c > @@ -331,10 +331,11 @@ nfsd_proc_create(struct svc_rqst *rqstp) > * echo thing > device-special-file-or-pipe > * by doing a CREATE with type==0 > */ > - resp->status = nfsd_permission(rqstp, > - newfhp->fh_export, > - newfhp->fh_dentry, > - NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); > + resp->status = nfsd_permission( > + &rqstp->rq_cred, > + newfhp->fh_export, > + newfhp->fh_dentry, > + NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); > if (resp->status && resp->status != nfserr_rofs) > goto out_unlock; > } > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c > index 29b1f3613800..0862f6ae86a9 100644 > --- a/fs/nfsd/vfs.c > +++ b/fs/nfsd/vfs.c > @@ -421,8 +421,9 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, > if (iap->ia_size < inode->i_size) { > __be32 err; > > - err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, > - NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); > + err = nfsd_permission(&rqstp->rq_cred, > + fhp->fh_export, fhp->fh_dentry, > + NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); > if (err) > return err; > } > @@ -814,7 +815,8 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor > > sresult |= map->access; > > - err2 = nfsd_permission(rqstp, export, dentry, map->how); > + err2 = nfsd_permission(&rqstp->rq_cred, export, > + dentry, map->how); > switch (err2) { > case nfs_ok: > result |= map->access; > @@ -1475,7 +1477,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, > dirp = d_inode(dentry); > > dchild = dget(resfhp->fh_dentry); > - err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE); > + err = nfsd_permission(&rqstp->rq_cred, fhp->fh_export, dentry, > + NFSD_MAY_CREATE); > if (err) > goto out; > > @@ -2255,9 +2258,9 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, in > return err; > } > > -static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp) > +static int exp_rdonly(struct svc_cred *cred, struct svc_export *exp) > { > - return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY; > + return nfsexp_flags(cred, exp) & NFSEXP_READONLY; > } > > #ifdef CONFIG_NFSD_V4 > @@ -2501,8 +2504,8 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, > * Check for a user's access permissions to this inode. > */ > __be32 > -nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, > - struct dentry *dentry, int acc) > +nfsd_permission(struct svc_cred *cred, struct svc_export *exp, > + struct dentry *dentry, int acc) > { > struct inode *inode = d_inode(dentry); > int err; > @@ -2533,7 +2536,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, > */ > if (!(acc & NFSD_MAY_LOCAL_ACCESS)) > if (acc & (NFSD_MAY_WRITE | NFSD_MAY_SATTR | NFSD_MAY_TRUNC)) { > - if (exp_rdonly(rqstp, exp) || > + if (exp_rdonly(cred, exp) || > __mnt_is_readonly(exp->ex_path.mnt)) > return nfserr_rofs; > if (/* (acc & NFSD_MAY_WRITE) && */ IS_IMMUTABLE(inode)) > diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h > index 57cd70062048..1565c1dc28b6 100644 > --- a/fs/nfsd/vfs.h > +++ b/fs/nfsd/vfs.h > @@ -153,7 +153,7 @@ __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, > __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, > struct kstatfs *, int access); > > -__be32 nfsd_permission(struct svc_rqst *, struct svc_export *, > +__be32 nfsd_permission(struct svc_cred *, struct svc_export *, > struct dentry *, int); > > void nfsd_filp_close(struct file *fp); Patch itself looks fine though.
Hi NeilBrown,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.10-rc6 next-20240701]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/NeilBrown/nfsd-introduce-__fh_verify-which-takes-explicit-nfsd_net-arg/20240701-122856
base: linus/master
patch link: https://lore.kernel.org/r/20240701025802.22985-3-neilb%40suse.de
patch subject: [PATCH 2/6] nfsd: add cred parameter to __fh_verify()
config: parisc-defconfig
compiler: hppa-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build):
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202407020129.uUBFQk9E-lkp@intel.com/
All warnings (new ones prefixed by >>):
fs/nfsd/nfsfh.c:334: warning: Function parameter or struct member 'nn' not described in '__fh_verify'
>> fs/nfsd/nfsfh.c:334: warning: Function parameter or struct member 'cred' not described in '__fh_verify'
fs/nfsd/nfsfh.c:334: warning: expecting prototype for fh_verify(). Prototype was for __fh_verify() instead
vim +334 fs/nfsd/nfsfh.c
03550fac06c4f0 J. Bruce Fields 2008-03-14 302
b3d47676d474ec J. Bruce Fields 2008-10-20 303 /**
b3d47676d474ec J. Bruce Fields 2008-10-20 304 * fh_verify - filehandle lookup and access checking
b3d47676d474ec J. Bruce Fields 2008-10-20 305 * @rqstp: pointer to current rpc request
b3d47676d474ec J. Bruce Fields 2008-10-20 306 * @fhp: filehandle to be verified
b3d47676d474ec J. Bruce Fields 2008-10-20 307 * @type: expected type of object pointed to by filehandle
b3d47676d474ec J. Bruce Fields 2008-10-20 308 * @access: type of access needed to object
b3d47676d474ec J. Bruce Fields 2008-10-20 309 *
b3d47676d474ec J. Bruce Fields 2008-10-20 310 * Look up a dentry from the on-the-wire filehandle, check the client's
b3d47676d474ec J. Bruce Fields 2008-10-20 311 * access to the export, and set the current task's credentials.
b3d47676d474ec J. Bruce Fields 2008-10-20 312 *
b3d47676d474ec J. Bruce Fields 2008-10-20 313 * Regardless of success or failure of fh_verify(), fh_put() should be
b3d47676d474ec J. Bruce Fields 2008-10-20 314 * called on @fhp when the caller is finished with the filehandle.
b3d47676d474ec J. Bruce Fields 2008-10-20 315 *
b3d47676d474ec J. Bruce Fields 2008-10-20 316 * fh_verify() may be called multiple times on a given filehandle, for
b3d47676d474ec J. Bruce Fields 2008-10-20 317 * example, when processing an NFSv4 compound. The first call will look
b3d47676d474ec J. Bruce Fields 2008-10-20 318 * up a dentry using the on-the-wire filehandle. Subsequent calls will
b3d47676d474ec J. Bruce Fields 2008-10-20 319 * skip the lookup and just perform the other checks and possibly change
b3d47676d474ec J. Bruce Fields 2008-10-20 320 * the current task's credentials.
03550fac06c4f0 J. Bruce Fields 2008-03-14 321 *
b3d47676d474ec J. Bruce Fields 2008-10-20 322 * @type specifies the type of object expected using one of the S_IF*
b3d47676d474ec J. Bruce Fields 2008-10-20 323 * constants defined in include/linux/stat.h. The caller may use zero
b3d47676d474ec J. Bruce Fields 2008-10-20 324 * to indicate that it doesn't care, or a negative integer to indicate
b3d47676d474ec J. Bruce Fields 2008-10-20 325 * that it expects something not of the given type.
03550fac06c4f0 J. Bruce Fields 2008-03-14 326 *
b3d47676d474ec J. Bruce Fields 2008-10-20 327 * @access is formed from the NFSD_MAY_* constants defined in
93f580a9a2413d Oleg Drokin 2016-07-07 328 * fs/nfsd/vfs.h.
03550fac06c4f0 J. Bruce Fields 2008-03-14 329 */
63e675e35f79ed NeilBrown 2024-07-01 330 static __be32
72924991777f5b NeilBrown 2024-07-01 331 __fh_verify(struct svc_rqst *rqstp,
72924991777f5b NeilBrown 2024-07-01 332 struct nfsd_net *nn, struct svc_cred *cred,
63e675e35f79ed NeilBrown 2024-07-01 333 struct svc_fh *fhp, umode_t type, int access)
03550fac06c4f0 J. Bruce Fields 2008-03-14 @334 {
20ad856e47323e Amir Goldstein 2021-01-06 335 struct svc_export *exp = NULL;
03550fac06c4f0 J. Bruce Fields 2008-03-14 336 struct dentry *dentry;
03550fac06c4f0 J. Bruce Fields 2008-03-14 337 __be32 error;
03550fac06c4f0 J. Bruce Fields 2008-03-14 338
03550fac06c4f0 J. Bruce Fields 2008-03-14 339 if (!fhp->fh_dentry) {
72924991777f5b NeilBrown 2024-07-01 340 error = nfsd_set_fh_dentry(rqstp, nn, cred, fhp);
03550fac06c4f0 J. Bruce Fields 2008-03-14 341 if (error)
03550fac06c4f0 J. Bruce Fields 2008-03-14 342 goto out;
864f0f61f829ba J. Bruce Fields 2009-11-25 343 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 344 dentry = fhp->fh_dentry;
^1da177e4c3f41 Linus Torvalds 2005-04-16 345 exp = fhp->fh_export;
051382885552e1 Chuck Lever 2022-06-21 346
051382885552e1 Chuck Lever 2022-06-21 347 trace_nfsd_fh_verify(rqstp, fhp, type, access);
051382885552e1 Chuck Lever 2022-06-21 348
6fa02839bf9412 J. Bruce Fields 2007-11-12 349 /*
864f0f61f829ba J. Bruce Fields 2009-11-25 350 * We still have to do all these permission checks, even when
864f0f61f829ba J. Bruce Fields 2009-11-25 351 * fh_dentry is already set:
864f0f61f829ba J. Bruce Fields 2009-11-25 352 * - fh_verify may be called multiple times with different
864f0f61f829ba J. Bruce Fields 2009-11-25 353 * "access" arguments (e.g. nfsd_proc_create calls
864f0f61f829ba J. Bruce Fields 2009-11-25 354 * fh_verify(...,NFSD_MAY_EXEC) first, then later (in
864f0f61f829ba J. Bruce Fields 2009-11-25 355 * nfsd_create) calls fh_verify(...,NFSD_MAY_CREATE).
864f0f61f829ba J. Bruce Fields 2009-11-25 356 * - in the NFSv4 case, the filehandle may have been filled
864f0f61f829ba J. Bruce Fields 2009-11-25 357 * in by fh_compose, and given a dentry, but further
864f0f61f829ba J. Bruce Fields 2009-11-25 358 * compound operations performed with that filehandle
864f0f61f829ba J. Bruce Fields 2009-11-25 359 * still need permissions checks. In the worst case, a
864f0f61f829ba J. Bruce Fields 2009-11-25 360 * mountpoint crossing may have changed the export
864f0f61f829ba J. Bruce Fields 2009-11-25 361 * options, and we may now need to use a different uid
864f0f61f829ba J. Bruce Fields 2009-11-25 362 * (for example, if different id-squashing options are in
864f0f61f829ba J. Bruce Fields 2009-11-25 363 * effect on the new filesystem).
6fa02839bf9412 J. Bruce Fields 2007-11-12 364 */
03a816b46d7eba Steve Dickson 2009-09-09 365 error = check_pseudo_root(rqstp, dentry, exp);
03a816b46d7eba Steve Dickson 2009-09-09 366 if (error)
03a816b46d7eba Steve Dickson 2009-09-09 367 goto out;
03a816b46d7eba Steve Dickson 2009-09-09 368
72924991777f5b NeilBrown 2024-07-01 369 error = nfsd_setuser_and_check_port(rqstp, cred, exp);
7fc90ec93a5eb7 J. Bruce Fields 2006-06-30 370 if (error)
7fc90ec93a5eb7 J. Bruce Fields 2006-06-30 371 goto out;
7fc90ec93a5eb7 J. Bruce Fields 2006-06-30 372
e75b23f9e323b1 J. Bruce Fields 2016-07-19 373 error = nfsd_mode_check(rqstp, dentry, type);
^1da177e4c3f41 Linus Torvalds 2005-04-16 374 if (error)
^1da177e4c3f41 Linus Torvalds 2005-04-16 375 goto out;
^1da177e4c3f41 Linus Torvalds 2005-04-16 376
9091224f3cff47 J. Bruce Fields 2007-07-17 377 /*
9091224f3cff47 J. Bruce Fields 2007-07-17 378 * pseudoflavor restrictions are not enforced on NLM,
9091224f3cff47 J. Bruce Fields 2007-07-17 379 * which clients virtually always use auth_sys for,
9091224f3cff47 J. Bruce Fields 2007-07-17 380 * even while using RPCSEC_GSS for NFS.
9091224f3cff47 J. Bruce Fields 2007-07-17 381 */
204f4ce75434c3 J. Bruce Fields 2011-04-08 382 if (access & NFSD_MAY_LOCK || access & NFSD_MAY_BYPASS_GSS)
04716e6621ff4a J. Bruce Fields 2008-08-07 383 goto skip_pseudoflavor_check;
04716e6621ff4a J. Bruce Fields 2008-08-07 384 /*
04716e6621ff4a J. Bruce Fields 2008-08-07 385 * Clients may expect to be able to use auth_sys during mount,
04716e6621ff4a J. Bruce Fields 2008-08-07 386 * even if they use gss for everything else; see section 2.3.2
04716e6621ff4a J. Bruce Fields 2008-08-07 387 * of rfc 2623.
04716e6621ff4a J. Bruce Fields 2008-08-07 388 */
04716e6621ff4a J. Bruce Fields 2008-08-07 389 if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
04716e6621ff4a J. Bruce Fields 2008-08-07 390 && exp->ex_path.dentry == dentry)
04716e6621ff4a J. Bruce Fields 2008-08-07 391 goto skip_pseudoflavor_check;
04716e6621ff4a J. Bruce Fields 2008-08-07 392
32c1eb0cd7ee00 Andy Adamson 2007-07-17 393 error = check_nfsd_access(exp, rqstp);
32c1eb0cd7ee00 Andy Adamson 2007-07-17 394 if (error)
32c1eb0cd7ee00 Andy Adamson 2007-07-17 395 goto out;
32c1eb0cd7ee00 Andy Adamson 2007-07-17 396
04716e6621ff4a J. Bruce Fields 2008-08-07 397 skip_pseudoflavor_check:
^1da177e4c3f41 Linus Torvalds 2005-04-16 398 /* Finally, check access permissions. */
72924991777f5b NeilBrown 2024-07-01 399 error = nfsd_permission(cred, exp, dentry, access);
^1da177e4c3f41 Linus Torvalds 2005-04-16 400 out:
93c128e709aec2 Jeff Layton 2022-10-12 401 trace_nfsd_fh_verify_err(rqstp, fhp, type, access, error);
^1da177e4c3f41 Linus Torvalds 2005-04-16 402 if (error == nfserr_stale)
4b14885411f74b Josef Bacik 2024-01-26 403 nfsd_stats_fh_stale_inc(nn, exp);
^1da177e4c3f41 Linus Torvalds 2005-04-16 404 return error;
^1da177e4c3f41 Linus Torvalds 2005-04-16 405 }
^1da177e4c3f41 Linus Torvalds 2005-04-16 406
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index e6beaaf4f170..93e33d1ee891 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c @@ -5,26 +5,26 @@ #include "nfsd.h" #include "auth.h" -int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) +int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp) { struct exp_flavor_info *f; struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; for (f = exp->ex_flavors; f < end; f++) { - if (f->pseudoflavor == rqstp->rq_cred.cr_flavor) + if (f->pseudoflavor == cred->cr_flavor) return f->flags; } return exp->ex_flags; } -int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) +int nfsd_setuser(struct svc_cred *cred, struct svc_export *exp) { struct group_info *rqgi; struct group_info *gi; struct cred *new; int i; - int flags = nfsexp_flags(rqstp, exp); + int flags = nfsexp_flags(cred, exp); /* discard any old override before preparing the new set */ revert_creds(get_cred(current_real_cred())); @@ -32,10 +32,10 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) if (!new) return -ENOMEM; - new->fsuid = rqstp->rq_cred.cr_uid; - new->fsgid = rqstp->rq_cred.cr_gid; + new->fsuid = cred->cr_uid; + new->fsgid = cred->cr_gid; - rqgi = rqstp->rq_cred.cr_group_info; + rqgi = cred->cr_group_info; if (flags & NFSEXP_ALLSQUASH) { new->fsuid = exp->ex_anon_uid; diff --git a/fs/nfsd/auth.h b/fs/nfsd/auth.h index dbd66424f600..fc75c5d90be4 100644 --- a/fs/nfsd/auth.h +++ b/fs/nfsd/auth.h @@ -12,6 +12,6 @@ * Set the current process's fsuid/fsgid etc to those of the NFS * client user */ -int nfsd_setuser(struct svc_rqst *, struct svc_export *); +int nfsd_setuser(struct svc_cred *, struct svc_export *); #endif /* LINUX_NFSD_AUTH_H */ diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h index 1a54d388d58d..2dbd15704a86 100644 --- a/fs/nfsd/export.h +++ b/fs/nfsd/export.h @@ -99,7 +99,8 @@ struct svc_expkey { #define EX_NOHIDE(exp) ((exp)->ex_flags & NFSEXP_NOHIDE) #define EX_WGATHER(exp) ((exp)->ex_flags & NFSEXP_GATHERED_WRITES) -int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp); +struct svc_cred; +int nfsexp_flags(struct svc_cred *cred, struct svc_export *exp); __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp); /* diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a20c2c9d7d45..eadb7d1a7f13 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -6889,7 +6889,8 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, nf = nfs4_find_file(s, flags); if (nf) { - status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, + status = nfsd_permission(&rqstp->rq_cred, + fhp->fh_export, fhp->fh_dentry, acc | NFSD_MAY_OWNER_OVERRIDE); if (status) { nfsd_file_put(nf); diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index e27ed27054ab..760684fa4b50 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -100,9 +100,10 @@ static bool nfsd_originating_port_ok(struct svc_rqst *rqstp, int flags) } static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, + struct svc_cred *cred, struct svc_export *exp) { - int flags = nfsexp_flags(rqstp, exp); + int flags = nfsexp_flags(cred, exp); /* Check if the request originated from a secure port. */ if (!nfsd_originating_port_ok(rqstp, flags)) { @@ -113,7 +114,7 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, } /* Set user creds for this exportpoint */ - return nfserrno(nfsd_setuser(rqstp, exp)); + return nfserrno(nfsd_setuser(cred, exp)); } static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, @@ -152,6 +153,7 @@ static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, * fh_dentry. */ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn, + struct svc_cred *cred, struct svc_fh *fhp) { struct knfsd_fh *fh = &fhp->fh_handle; @@ -230,7 +232,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn, put_cred(override_creds(new)); put_cred(new); } else { - error = nfsd_setuser_and_check_port(rqstp, exp); + error = nfsd_setuser_and_check_port(rqstp, cred, exp); if (error) goto out; } @@ -326,7 +328,8 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct nfsd_net *nn, * fs/nfsd/vfs.h. */ static __be32 -__fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, +__fh_verify(struct svc_rqst *rqstp, + struct nfsd_net *nn, struct svc_cred *cred, struct svc_fh *fhp, umode_t type, int access) { struct svc_export *exp = NULL; @@ -334,7 +337,7 @@ __fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, __be32 error; if (!fhp->fh_dentry) { - error = nfsd_set_fh_dentry(rqstp, nn, fhp); + error = nfsd_set_fh_dentry(rqstp, nn, cred, fhp); if (error) goto out; } @@ -363,7 +366,7 @@ __fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, if (error) goto out; - error = nfsd_setuser_and_check_port(rqstp, exp); + error = nfsd_setuser_and_check_port(rqstp, cred, exp); if (error) goto out; @@ -393,7 +396,7 @@ __fh_verify(struct svc_rqst *rqstp, struct nfsd_net *nn, skip_pseudoflavor_check: /* Finally, check access permissions. */ - error = nfsd_permission(rqstp, exp, dentry, access); + error = nfsd_permission(cred, exp, dentry, access); out: trace_nfsd_fh_verify_err(rqstp, fhp, type, access, error); if (error == nfserr_stale) @@ -405,6 +408,7 @@ __be32 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) { return __fh_verify(rqstp, net_generic(SVC_NET(rqstp), nfsd_net_id), + &rqstp->rq_cred, fhp, type, access); } diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 36370b957b63..97aab34593ef 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -331,10 +331,11 @@ nfsd_proc_create(struct svc_rqst *rqstp) * echo thing > device-special-file-or-pipe * by doing a CREATE with type==0 */ - resp->status = nfsd_permission(rqstp, - newfhp->fh_export, - newfhp->fh_dentry, - NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); + resp->status = nfsd_permission( + &rqstp->rq_cred, + newfhp->fh_export, + newfhp->fh_dentry, + NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); if (resp->status && resp->status != nfserr_rofs) goto out_unlock; } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 29b1f3613800..0862f6ae86a9 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -421,8 +421,9 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, if (iap->ia_size < inode->i_size) { __be32 err; - err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, - NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); + err = nfsd_permission(&rqstp->rq_cred, + fhp->fh_export, fhp->fh_dentry, + NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); if (err) return err; } @@ -814,7 +815,8 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor sresult |= map->access; - err2 = nfsd_permission(rqstp, export, dentry, map->how); + err2 = nfsd_permission(&rqstp->rq_cred, export, + dentry, map->how); switch (err2) { case nfs_ok: result |= map->access; @@ -1475,7 +1477,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, dirp = d_inode(dentry); dchild = dget(resfhp->fh_dentry); - err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE); + err = nfsd_permission(&rqstp->rq_cred, fhp->fh_export, dentry, + NFSD_MAY_CREATE); if (err) goto out; @@ -2255,9 +2258,9 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, in return err; } -static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp) +static int exp_rdonly(struct svc_cred *cred, struct svc_export *exp) { - return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY; + return nfsexp_flags(cred, exp) & NFSEXP_READONLY; } #ifdef CONFIG_NFSD_V4 @@ -2501,8 +2504,8 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, * Check for a user's access permissions to this inode. */ __be32 -nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, - struct dentry *dentry, int acc) +nfsd_permission(struct svc_cred *cred, struct svc_export *exp, + struct dentry *dentry, int acc) { struct inode *inode = d_inode(dentry); int err; @@ -2533,7 +2536,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, */ if (!(acc & NFSD_MAY_LOCAL_ACCESS)) if (acc & (NFSD_MAY_WRITE | NFSD_MAY_SATTR | NFSD_MAY_TRUNC)) { - if (exp_rdonly(rqstp, exp) || + if (exp_rdonly(cred, exp) || __mnt_is_readonly(exp->ex_path.mnt)) return nfserr_rofs; if (/* (acc & NFSD_MAY_WRITE) && */ IS_IMMUTABLE(inode)) diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 57cd70062048..1565c1dc28b6 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -153,7 +153,7 @@ __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *, __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *, struct kstatfs *, int access); -__be32 nfsd_permission(struct svc_rqst *, struct svc_export *, +__be32 nfsd_permission(struct svc_cred *, struct svc_export *, struct dentry *, int); void nfsd_filp_close(struct file *fp);
__fh_verify() now takes a 'cred' parameter and never dereferences rqstp->rq_cred. nfsd_permission(), nfsd_setuser() and nfsexp_flags() only never needed the cred out of rqstp, so we now pass in the cred explicitly and not the rqstp. nfsd_originating_port_ok() is NOT passed a cred despite that it uses one. This function is not useful when rqstp is NULL and a future patch will address that. Signed-off-by: NeilBrown <neilb@suse.de> --- fs/nfsd/auth.c | 14 +++++++------- fs/nfsd/auth.h | 2 +- fs/nfsd/export.h | 3 ++- fs/nfsd/nfs4state.c | 3 ++- fs/nfsd/nfsfh.c | 18 +++++++++++------- fs/nfsd/nfsproc.c | 9 +++++---- fs/nfsd/vfs.c | 21 ++++++++++++--------- fs/nfsd/vfs.h | 2 +- 8 files changed, 41 insertions(+), 31 deletions(-)