From 79a8cb640686ba35f63db73e1d0c2d286f3b964f Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Wed, 9 Sep 2009 15:06:05 -0400 Subject: [PATCH] --- yaml --- r: 177207 b: refs/heads/master c: 03a816b46d7eba78da11e4025f0af195b32fa464 h: refs/heads/master i: 177205: 05f3a8f1293dcd3ab8cb39229b3396247e11ab85 177203: 73f68eb6534c90544ca1395465a3d69d97bfb601 177199: 5044ee80b97cfbad8a3b06ce31d98e49eaba2972 v: v3 --- [refs] | 2 +- trunk/fs/nfsd/nfsd.h | 5 +++++ trunk/fs/nfsd/nfsfh.c | 34 ++++++++++++++++++++++++++++++++++ trunk/fs/nfsd/vfs.c | 6 ------ 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/[refs] b/[refs] index cf5e0eaa0a18..6a5e673e535f 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: f2ca7153ca49a407ea1c7232c9fa7e9849f03f9c +refs/heads/master: 03a816b46d7eba78da11e4025f0af195b32fa464 diff --git a/trunk/fs/nfsd/nfsd.h b/trunk/fs/nfsd/nfsd.h index 74f67c2aca34..ac121ad16540 100644 --- a/trunk/fs/nfsd/nfsd.h +++ b/trunk/fs/nfsd/nfsd.h @@ -70,6 +70,11 @@ int nfsd_create_serv(void); extern int nfsd_max_blksize; +static inline int nfsd_v4client(struct svc_rqst *rq) +{ + return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; +} + /* * NFSv4 State */ diff --git a/trunk/fs/nfsd/nfsfh.c b/trunk/fs/nfsd/nfsfh.c index 951938d6c495..44812c32e51e 100644 --- a/trunk/fs/nfsd/nfsfh.c +++ b/trunk/fs/nfsd/nfsfh.c @@ -103,6 +103,36 @@ static __be32 nfsd_setuser_and_check_port(struct svc_rqst *rqstp, return nfserrno(nfsd_setuser(rqstp, exp)); } +static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, + struct dentry *dentry, struct svc_export *exp) +{ + if (!(exp->ex_flags & NFSEXP_V4ROOT)) + return nfs_ok; + /* + * v2/v3 clients have no need for the V4ROOT export--they use + * the mount protocl instead; also, further V4ROOT checks may be + * in v4-specific code, in which case v2/v3 clients could bypass + * them. + */ + if (!nfsd_v4client(rqstp)) + return nfserr_stale; + /* + * We're exposing only the directories and symlinks that have to be + * traversed on the way to real exports: + */ + if (unlikely(!S_ISDIR(dentry->d_inode->i_mode) && + !S_ISLNK(dentry->d_inode->i_mode))) + return nfserr_stale; + /* + * A pseudoroot export gives permission to access only one + * single directory; the kernel has to make another upcall + * before granting access to anything else under it: + */ + if (unlikely(dentry != exp->ex_path.dentry)) + return nfserr_stale; + return nfs_ok; +} + /* * Use the given filehandle to look up the corresponding export and * dentry. On success, the results are used to set fh_export and @@ -299,6 +329,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) * (for example, if different id-squashing options are in * effect on the new filesystem). */ + error = check_pseudo_root(rqstp, dentry, exp); + if (error) + goto out; + error = nfsd_setuser_and_check_port(rqstp, exp); if (error) goto out; diff --git a/trunk/fs/nfsd/vfs.c b/trunk/fs/nfsd/vfs.c index a0015a958aef..f6ca32b07e11 100644 --- a/trunk/fs/nfsd/vfs.c +++ b/trunk/fs/nfsd/vfs.c @@ -72,12 +72,6 @@ struct raparm_hbucket { #define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1) static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE]; -static inline int -nfsd_v4client(struct svc_rqst *rq) -{ - return rq->rq_prog == NFS_PROGRAM && rq->rq_vers == 4; -} - /* * Called from nfsd_lookup and encode_dirent. Check if we have crossed * a mount point.