On Fri, 2008-02-08 at 16:03 -0500, J. Bruce Fields wrote:
> On Fri, Feb 08, 2008 at 03:07:57PM -0500, Peter Staubach wrote:
> > J. Bruce Fields wrote:
> >> From: Frank Filz <[EMAIL PROTECTED]>
> >>
> >> This patch addresses a compatibility issue with a Linux NFS server and
> >> AIX NFS client.
> >>
> >> I have exported /export as fsid=0 with sec=krb5:krb5i
> >> I have mount --bind /home onto /export/home
> >> I have exported /export/home with sec=krb5i
> >>
> >> The AIX client mounts / -o sec=krb5:krb5i onto /mnt
> >>
> >> If I do an ls /mnt, the AIX client gets a permission error. Looking at
> >> the network traceIwe see a READDIR looking for attributes
> >> FATTR4_RDATTR_ERROR and FATTR4_MOUNTED_ON_FILEID. The response gives a
> >> NFS4ERR_WRONGSEC which the AIX client is not expecting.
> >>
> >> Since the AIX client is only asking for an attribute that is an
> >> attribute of the parent file system (pseudo root in my example), it
> >> seems reasonable that there should not be an error.
> >>
> >>
> >
> > Can we go through this explanation one more time, a little more
> > slowly, please? I am not following it.
> >
> > It is my understanding that FATTR4_RDATTR_ERROR simply says
> > to return a magic value to indicate that the requested attributes
> > could not be retrieved during a READDIR operation. It is also
> > my understanding that the FATTR4_MOUNTED_ON_FILEID returns either
> > the fileid of the entry in the directory or the fileid of the
> > directory which is the root of the mount point which is mounted
> > on top of the entry in the directory.
>
> No, it's the fileid of the directory underneath (the mounted-on
> directory), not of the directory that's mounted on top of it--that would
> be just the regular fileid. Does that clear up the confusion?
READDIR with cross-mounts is definitely confusing. Remember READDIR is
reading some directory .../a/ that is part of file system #1. Within
that directory is a mountpoint, .../a/fs2 for a new file system (#2). A
cross mount. The client is currently using a security flavor that is
valid for file system #1 but not valid for file system #2.
Since .../a/fs2 is the root of a new file system, it probably has a
FILEID like 2 or something. However, there is .../a/fs2 which is a file
in file system #1 (perhaps with a FILEID like 356).
FATTR4_MOUNTED_ON_FILEID will return 356 instead of 2. Since the client
is only asking for the file names in .../a/ and their
FATTR4_MOUNTED_ON_FILEID, the READDIR is clearly asking for information
that does not at all depend on access to (and permission to use) file
system #2 (in fact, the exports might even deny this client access to
file system #2 no matter what security flavor it uses). Since the client
is not asking for anything that it doesn't have permission to ask for
(if file system #2 were not currently mounted, this READDIR would
respond with exactly the same results, and the security of file system
#2 would not come into play at all), there is no reason to report an
error (and not supply the attribute).
> > So, given all of this, why is the right thing to do to return
> > the fileid of the entry in the directory, even though it is
> > mounted on top of? Why isn't the right thing to do to return
> > NFS4ERR_WRONGSEC per page 206 in rfc3530?
> >
> > Perhaps I am not following the bind mount properly?
> >
> > A little more below --
> >
> >
> >> In discussing this issue with Bruce Fields, I initially proposed
> >> ignoring the error in nfsd4_encode_dirent_fattr() if all that was being
> >> asked for was FATTR4_RDATTR_ERROR and FATTR4_MOUNTED_ON_FILEID, however,
> >> Bruce suggested that we avoid calling cross_mnt() if only these
> >> attributes are requested.
> >>
> >> The following patch implements bypassing cross_mnt() if only
> >> FATTR4_RDATTR_ERROR and FATTR4_MOUNTED_ON_FILEID are called. Since there
> >> is some complexity in the code in nfsd4_encode_fattr(), I didn't want to
> >> duplicate code (and introduce a maintenance nightmare), so I added a
> >> parameter to nfsd4_encode_fattr() that indicates whether it should
> >> ignore cross mounts and simply fill in the attribute using the passed in
> >> dentry as opposed to it's parent.
> >>
> >> Signed-off-by: Frank Filz <[EMAIL PROTECTED]>
> >> Signed-off-by: J. Bruce Fields <[EMAIL PROTECTED]>
> >> ---
> >> fs/nfsd/nfs4proc.c | 2 +-
> >> fs/nfsd/nfs4xdr.c | 27 ++++++++++++++++++++++-----
> >> include/linux/nfsd/xdr4.h | 2 +-
> >> 3 files changed, 24 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> >> index 18ead17..c593db0 100644
> >> --- a/fs/nfsd/nfs4proc.c
> >> +++ b/fs/nfsd/nfs4proc.c
> >> @@ -750,7 +750,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct
> >> nfsd4_compound_state *cstate,
> >> cstate->current_fh.fh_export,
> >> cstate->current_fh.fh_dentry, buf,
> >> &count, verify->ve_bmval,
> >> - rqstp);
> >> + rqstp, 0);
> >> /* this means that nfsd4_encode_fattr() ran out of space */
> >> if (status == nfserr_resource && count == 0)
> >> diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
> >> index 25c7ae2..2d94b9b 100644
> >> --- a/fs/nfsd/nfs4xdr.c
> >> +++ b/fs/nfsd/nfs4xdr.c
> >> @@ -1453,7 +1453,7 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0,
> >> u32 *bmval1, u32 *rdattr_err)
> >> __be32
> >> nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
> >> struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
> >> - struct svc_rqst *rqstp)
> >> + struct svc_rqst *rqstp, int ignore_crossmnt)
> >> {
> >> u32 bmval0 = bmval[0];
> >> u32 bmval1 = bmval[1];
> >> @@ -1833,7 +1833,12 @@ out_acl:
> >> if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) {
> >> if ((buflen -= 8) < 0)
> >> goto out_resource;
> >> - if (exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
> >> + /*
> >> + * Get parent's attributes if not ignoring crossmount
> >> + * and this is the root of a cross-mounted filesystem.
> >> + */
> >> + if (ignore_crossmnt == 0 &&
> >> + exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) {
> >> err = vfs_getattr(exp->ex_mnt->mnt_parent,
> >> exp->ex_mnt->mnt_mountpoint, &stat);
> >> if (err)
> >> @@ -1869,13 +1874,25 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
> >> struct svc_export *exp = cd->rd_fhp->fh_export;
> >> struct dentry *dentry;
> >> __be32 nfserr;
> >> + int ignore_crossmnt = 0;
> >> dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
> >> if (IS_ERR(dentry))
> >> return nfserrno(PTR_ERR(dentry));
> >> exp_get(exp);
> >> - if (d_mountpoint(dentry)) {
> >> + /*
> >> + * In the case of a mountpoint, the client may be asking for
> >> + * attributes that are only properties of the underlying filesystem
> >> + * as opposed to the cross-mounted file system. In such a case,
> >> + * we will not follow the cross mount and will fill the attribtutes
> >> + * directly from the mountpoint dentry.
> >> + */
> >> + if (d_mountpoint(dentry) &&
> >> + (cd->rd_bmval[0] & ~FATTR4_WORD0_RDATTR_ERROR) == 0 &&
> >> + (cd->rd_bmval[1] & ~FATTR4_WORD1_MOUNTED_ON_FILEID) == 0)
> >>
> >
> > These are some odd looking tests. What is the real intention
> > for these tests? They don't test just for requests with just
> > RDATTR_ERROR and MOUNTED_ON_FILEID set. They will trigger
> > whether or not either or neither is set as well.
>
> Right. The test is meant to fail iff someone requests an attribute
> other than those two. (Note the different rd_bmval[] array indices.)
>
> (Actually, I suppose we could also allow requests for lease_time. Patch
> welcomed....)
Yep, intention here is to bypass the crossmount if the only attributes
requested are properties of file system #1 (per above discussion).
Frank Filz
-
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html