From 7d818a7b8fc8d26c24ee44ed1c5dece69455a7b6 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 15 Aug 2011 16:59:55 -0400 Subject: nfsd: open-code special directory-hardlink check We allow the fh_verify caller to specify that any object *except* those of a given type is allowed, by passing a negative type. But only one caller actually uses it. Open-code that check in the one caller. Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs/nfsd/vfs.c') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index fd0acca5370a..0c92a17d1770 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1632,10 +1632,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_CREATE); if (err) goto out; - err = fh_verify(rqstp, tfhp, -S_IFDIR, NFSD_MAY_NOP); + err = fh_verify(rqstp, tfhp, 0, NFSD_MAY_NOP); if (err) goto out; - + err = nfserr_isdir; + if (S_ISDIR(tfhp->fh_dentry->d_inode->i_mode)) + goto out; err = nfserr_perm; if (!len) goto out; -- cgit v1.2.3 From e281d8100995133dc65e00b1dec8f84b91b6e8c3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 15 Aug 2011 16:57:07 -0400 Subject: nfsd4: fix incorrect comment in nfsd4_set_nfs4_acl Zero means "I don't care what kind of file this is". And that's probably what we want--acls are also settable at least on directories, and if the filesystem doesn't want them on other objects, leave it to it to complain. Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfsd/vfs.c') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 0c92a17d1770..4c22870293e6 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -502,7 +502,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned int flags = 0; /* Get inode */ - error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); + error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); if (error) return error; -- cgit v1.2.3 From a043226bc140a2c1dde162246d68a67e5043e6b2 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 25 Aug 2011 10:48:39 -0400 Subject: nfsd4: permit read opens of executable-only files A client that wants to execute a file must be able to read it. Read opens over nfs are therefore implicitly allowed for executable files even when those files are not readable. NFSv2/v3 get this right by using a passed-in NFSD_MAY_OWNER_OVERRIDE on read requests, but NFSv4 has gotten this wrong ever since dc730e173785e29b297aa605786c94adaffe2544 "nfsd4: fix owner-override on open", when we realized that the file owner shouldn't override permissions on non-reclaim NFSv4 opens. So we can't use NFSD_MAY_OWNER_OVERRIDE to tell nfsd_permission to allow reads of executable files. So, do the same thing we do whenever we encounter another weird NFS permission nit: define yet another NFSD_MAY_* flag. The industry's future standardization on 128-bit processors will be motivated primarily by the need for integers with enough bits for all the NFSD_MAY_* flags. Reported-by: Leonardo Borda Cc: stable@kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 2 ++ fs/nfsd/vfs.c | 3 ++- fs/nfsd/vfs.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'fs/nfsd/vfs.c') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 479ffb185df9..b5530984db91 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -156,6 +156,8 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) return nfserr_inval; + accmode |= NFSD_MAY_READ_IF_EXEC; + if (open->op_share_access & NFS4_SHARE_ACCESS_READ) accmode |= NFSD_MAY_READ; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4c22870293e6..75c35fa46155 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2116,7 +2116,8 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && - acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) + (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || + acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) err = inode_permission(inode, MAY_EXEC); return err? nfserrno(err) : 0; diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index e0bbac04d1dd..a22e40e27861 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -25,6 +25,7 @@ #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 #define NFSD_MAY_NOT_BREAK_LEASE 512 #define NFSD_MAY_BYPASS_GSS 1024 +#define NFSD_MAY_READ_IF_EXEC 2048 #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) -- cgit v1.2.3 From 11fcee0293a6d9f0973e04f8b3fb6cd15a55bcce Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 12 Sep 2011 19:37:26 -0400 Subject: NFSD: Add a cache for fs_locations information Signed-off-by: Trond Myklebust [ cel: since this is server-side, use nfsd4_ prefix instead of nfs4_ prefix. ] [ cel: implement S_ISVTX filter in bfields-normal form ] Signed-off-by: Chuck Lever Reviewed-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsd.h | 7 +++++++ fs/nfsd/vfs.c | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) (limited to 'fs/nfsd/vfs.c') diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 8da03e16ab35..58134a23fdfb 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -361,6 +361,13 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) #define NFSD_SUPPATTR_EXCLCREAT_WORD2 \ NFSD_WRITEABLE_ATTRS_WORD2 +extern int nfsd4_is_junction(struct dentry *dentry); +#else +static inline int nfsd4_is_junction(struct dentry *dentry) +{ + return 0; +} + #endif /* CONFIG_NFSD_V4 */ #endif /* LINUX_NFSD_NFSD_H */ diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 75c35fa46155..4dd91283d039 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -168,6 +168,8 @@ int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp) { if (d_mountpoint(dentry)) return 1; + if (nfsd4_is_junction(dentry)) + return 1; if (!(exp->ex_flags & NFSEXP_V4ROOT)) return 0; return dentry->d_inode != NULL; @@ -592,6 +594,22 @@ nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_ac return error; } +#define NFSD_XATTR_JUNCTION_PREFIX XATTR_TRUSTED_PREFIX "junction." +#define NFSD_XATTR_JUNCTION_TYPE NFSD_XATTR_JUNCTION_PREFIX "type" +int nfsd4_is_junction(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + + if (inode == NULL) + return 0; + if (inode->i_mode & S_IXUGO) + return 0; + if (!(inode->i_mode & S_ISVTX)) + return 0; + if (vfs_getxattr(dentry, NFSD_XATTR_JUNCTION_TYPE, NULL, 0) <= 0) + return 0; + return 1; +} #endif /* defined(CONFIG_NFSD_V4) */ #ifdef CONFIG_NFSD_V3 -- cgit v1.2.3 From 856121b2e83bd64bffdc8de449d24c9295e92ff3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 13 Oct 2011 11:37:11 -0400 Subject: nfsd4: warn on open failure after create If we create the object and then return failure to the client, we're left with an unexpected file in the filesystem. I'm trying to eliminate such cases but not 100% sure I have so an assertion might be helpful for now. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 7 ++++--- fs/nfsd/vfs.c | 2 +- fs/nfsd/vfs.h | 2 +- fs/nfsd/xdr4.h | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'fs/nfsd/vfs.c') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 10b50d78bdc3..710b97b7a2f3 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -194,7 +194,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o { struct svc_fh resfh; __be32 status; - int created = 0; fh_init(&resfh, NFS4_FHSIZE); open->op_truncate = 0; @@ -223,7 +222,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o open->op_fname.len, &open->op_iattr, &resfh, open->op_createmode, (u32 *)open->op_verf.data, - &open->op_truncate, &created); + &open->op_truncate, &open->op_created); /* * Following rfc 3530 14.2.16, use the returned bitmask @@ -253,7 +252,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o /* set reply cache */ fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh, &resfh.fh_handle); - if (!created) + if (!open->op_created) status = do_open_permission(rqstp, current_fh, open, NFSD_MAY_NOP); @@ -318,6 +317,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* We don't yet support WANT bits: */ open->op_share_access &= NFS4_SHARE_ACCESS_MASK; + open->op_created = 0; /* * RFC5661 18.51.3 * Before RECLAIM_COMPLETE done, server should deny new lock @@ -408,6 +408,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * set, (2) sets open->op_stateid, (3) sets open->op_delegation. */ status = nfsd4_process_open2(rqstp, &cstate->current_fh, open); + WARN_ON(status && open->op_created); out: nfsd4_cleanup_open_state(open, status); if (open->op_openowner) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4dd91283d039..7a2e442623c8 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1370,7 +1370,7 @@ __be32 do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, char *fname, int flen, struct iattr *iap, struct svc_fh *resfhp, int createmode, u32 *verifier, - int *truncp, int *created) + bool *truncp, bool *created) { struct dentry *dentry, *dchild = NULL; struct inode *dirp; diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 503f3bf11abd..3f54ad03bb2b 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -62,7 +62,7 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, char *name, int len, struct iattr *attrs, struct svc_fh *res, int createmode, - u32 *verifier, int *truncp, int *created); + u32 *verifier, bool *truncp, bool *created); __be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, loff_t, unsigned long); #endif /* CONFIG_NFSD_V3 */ diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index ce8c59196b4e..e3057350eea1 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -226,7 +226,8 @@ struct nfsd4_open { u32 op_recall; /* recall */ struct nfsd4_change_info op_cinfo; /* response */ u32 op_rflags; /* response */ - int op_truncate; /* used during processing */ + bool op_truncate; /* used during processing */ + bool op_created; /* used during processing */ struct nfs4_openowner *op_openowner; /* used during processing */ struct nfs4_file *op_file; /* used during processing */ struct nfs4_ol_stateid *op_stp; /* used during processing */ -- cgit v1.2.3