aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@netapp.com>2012-09-10 14:00:46 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-10-01 18:20:11 -0400
commit6168f62cbde8dcf4f58255794efbcdb8df603959 (patch)
tree897bac0b7539172aa171365337d964f7984b1a80
parent57a51048da742c764b6ce5d028c7f334ae04d363 (diff)
NFSv4: Add ACCESS operation to OPEN compound
The OPEN operation has no way to differentiate an open for read and an open for execution - both look like read to the server. This allowed users to read files that didn't have READ access but did have EXEC access, which is obviously wrong. This patch adds an ACCESS call to the OPEN compound to handle the difference between OPENs for reading and execution. Since we're going through the trouble of calling ACCESS, we check all possible access bits and cache the results hopefully avoiding an ACCESS call in the future. Signed-off-by: Weston Andros Adamson <dros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/dir.c16
-rw-r--r--fs/nfs/nfs4proc.c52
-rw-r--r--fs/nfs/nfs4xdr.c16
-rw-r--r--include/linux/nfs_fs.h2
-rw-r--r--include/linux/nfs_xdr.h3
5 files changed, 76 insertions, 13 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 627f108ede23..ce8cb926526b 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2072,7 +2072,7 @@ found:
2072 nfs_access_free_entry(entry); 2072 nfs_access_free_entry(entry);
2073} 2073}
2074 2074
2075static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) 2075void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
2076{ 2076{
2077 struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL); 2077 struct nfs_access_entry *cache = kmalloc(sizeof(*cache), GFP_KERNEL);
2078 if (cache == NULL) 2078 if (cache == NULL)
@@ -2098,6 +2098,20 @@ static void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *s
2098 spin_unlock(&nfs_access_lru_lock); 2098 spin_unlock(&nfs_access_lru_lock);
2099 } 2099 }
2100} 2100}
2101EXPORT_SYMBOL_GPL(nfs_access_add_cache);
2102
2103void nfs_access_set_mask(struct nfs_access_entry *entry, u32 access_result)
2104{
2105 entry->mask = 0;
2106 if (access_result & NFS4_ACCESS_READ)
2107 entry->mask |= MAY_READ;
2108 if (access_result &
2109 (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
2110 entry->mask |= MAY_WRITE;
2111 if (access_result & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
2112 entry->mask |= MAY_EXEC;
2113}
2114EXPORT_SYMBOL_GPL(nfs_access_set_mask);
2101 2115
2102static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) 2116static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
2103{ 2117{
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 471a75f11ea2..5b3207f557d9 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -104,6 +104,8 @@ static int nfs4_map_errors(int err)
104 return -EACCES; 104 return -EACCES;
105 case -NFS4ERR_MINOR_VERS_MISMATCH: 105 case -NFS4ERR_MINOR_VERS_MISMATCH:
106 return -EPROTONOSUPPORT; 106 return -EPROTONOSUPPORT;
107 case -NFS4ERR_ACCESS:
108 return -EACCES;
107 default: 109 default:
108 dprintk("%s could not handle NFSv4 error %d\n", 110 dprintk("%s could not handle NFSv4 error %d\n",
109 __func__, -err); 111 __func__, -err);
@@ -860,6 +862,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
860 p->o_arg.fh = NFS_FH(dir); 862 p->o_arg.fh = NFS_FH(dir);
861 p->o_arg.open_flags = flags; 863 p->o_arg.open_flags = flags;
862 p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE); 864 p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
865 /* ask server to check for all possible rights as results are cached */
866 p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
867 NFS4_ACCESS_EXTEND | NFS4_ACCESS_EXECUTE;
863 p->o_arg.clientid = server->nfs_client->cl_clientid; 868 p->o_arg.clientid = server->nfs_client->cl_clientid;
864 p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time); 869 p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
865 p->o_arg.id.uniquifier = sp->so_seqid.owner_id; 870 p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
@@ -1643,6 +1648,39 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
1643 return status; 1648 return status;
1644} 1649}
1645 1650
1651static int nfs4_opendata_access(struct rpc_cred *cred,
1652 struct nfs4_opendata *opendata,
1653 struct nfs4_state *state, fmode_t fmode)
1654{
1655 struct nfs_access_entry cache;
1656 u32 mask;
1657
1658 /* access call failed or for some reason the server doesn't
1659 * support any access modes -- defer access call until later */
1660 if (opendata->o_res.access_supported == 0)
1661 return 0;
1662
1663 mask = 0;
1664 if (fmode & FMODE_READ)
1665 mask |= MAY_READ;
1666 if (fmode & FMODE_WRITE)
1667 mask |= MAY_WRITE;
1668 if (fmode & FMODE_EXEC)
1669 mask |= MAY_EXEC;
1670
1671 cache.cred = cred;
1672 cache.jiffies = jiffies;
1673 nfs_access_set_mask(&cache, opendata->o_res.access_result);
1674 nfs_access_add_cache(state->inode, &cache);
1675
1676 if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
1677 return 0;
1678
1679 /* even though OPEN succeeded, access is denied. Close the file */
1680 nfs4_close_state(state, fmode);
1681 return -NFS4ERR_ACCESS;
1682}
1683
1646/* 1684/*
1647 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata 1685 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
1648 */ 1686 */
@@ -1900,6 +1938,10 @@ static int _nfs4_do_open(struct inode *dir,
1900 if (server->caps & NFS_CAP_POSIX_LOCK) 1938 if (server->caps & NFS_CAP_POSIX_LOCK)
1901 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags); 1939 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
1902 1940
1941 status = nfs4_opendata_access(cred, opendata, state, fmode);
1942 if (status != 0)
1943 goto err_opendata_put;
1944
1903 if (opendata->o_arg.open_flags & O_EXCL) { 1945 if (opendata->o_arg.open_flags & O_EXCL) {
1904 nfs4_exclusive_attrset(opendata, sattr); 1946 nfs4_exclusive_attrset(opendata, sattr);
1905 1947
@@ -1945,7 +1987,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
1945 struct nfs4_state *res; 1987 struct nfs4_state *res;
1946 int status; 1988 int status;
1947 1989
1948 fmode &= FMODE_READ|FMODE_WRITE; 1990 fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
1949 do { 1991 do {
1950 status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, 1992 status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
1951 &res, ctx_th); 1993 &res, ctx_th);
@@ -2771,13 +2813,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
2771 2813
2772 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); 2814 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
2773 if (!status) { 2815 if (!status) {
2774 entry->mask = 0; 2816 nfs_access_set_mask(entry, res.access);
2775 if (res.access & NFS4_ACCESS_READ)
2776 entry->mask |= MAY_READ;
2777 if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
2778 entry->mask |= MAY_WRITE;
2779 if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
2780 entry->mask |= MAY_EXEC;
2781 nfs_refresh_inode(inode, res.fattr); 2817 nfs_refresh_inode(inode, res.fattr);
2782 } 2818 }
2783 nfs_free_fattr(res.fattr); 2819 nfs_free_fattr(res.fattr);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 7ab29abb3160..657483c34e28 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -447,12 +447,14 @@ static int nfs4_stat_to_errno(int);
447 encode_sequence_maxsz + \ 447 encode_sequence_maxsz + \
448 encode_putfh_maxsz + \ 448 encode_putfh_maxsz + \
449 encode_open_maxsz + \ 449 encode_open_maxsz + \
450 encode_access_maxsz + \
450 encode_getfh_maxsz + \ 451 encode_getfh_maxsz + \
451 encode_getattr_maxsz) 452 encode_getattr_maxsz)
452#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ 453#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
453 decode_sequence_maxsz + \ 454 decode_sequence_maxsz + \
454 decode_putfh_maxsz + \ 455 decode_putfh_maxsz + \
455 decode_open_maxsz + \ 456 decode_open_maxsz + \
457 decode_access_maxsz + \
456 decode_getfh_maxsz + \ 458 decode_getfh_maxsz + \
457 decode_getattr_maxsz) 459 decode_getattr_maxsz)
458#define NFS4_enc_open_confirm_sz \ 460#define NFS4_enc_open_confirm_sz \
@@ -467,11 +469,13 @@ static int nfs4_stat_to_errno(int);
467 encode_sequence_maxsz + \ 469 encode_sequence_maxsz + \
468 encode_putfh_maxsz + \ 470 encode_putfh_maxsz + \
469 encode_open_maxsz + \ 471 encode_open_maxsz + \
472 encode_access_maxsz + \
470 encode_getattr_maxsz) 473 encode_getattr_maxsz)
471#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \ 474#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \
472 decode_sequence_maxsz + \ 475 decode_sequence_maxsz + \
473 decode_putfh_maxsz + \ 476 decode_putfh_maxsz + \
474 decode_open_maxsz + \ 477 decode_open_maxsz + \
478 decode_access_maxsz + \
475 decode_getattr_maxsz) 479 decode_getattr_maxsz)
476#define NFS4_enc_open_downgrade_sz \ 480#define NFS4_enc_open_downgrade_sz \
477 (compound_encode_hdr_maxsz + \ 481 (compound_encode_hdr_maxsz + \
@@ -2220,6 +2224,7 @@ static void nfs4_xdr_enc_open(struct rpc_rqst *req, struct xdr_stream *xdr,
2220 encode_putfh(xdr, args->fh, &hdr); 2224 encode_putfh(xdr, args->fh, &hdr);
2221 encode_open(xdr, args, &hdr); 2225 encode_open(xdr, args, &hdr);
2222 encode_getfh(xdr, &hdr); 2226 encode_getfh(xdr, &hdr);
2227 encode_access(xdr, args->access, &hdr);
2223 encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr); 2228 encode_getfattr_open(xdr, args->bitmask, args->open_bitmap, &hdr);
2224 encode_nops(&hdr); 2229 encode_nops(&hdr);
2225} 2230}
@@ -2256,6 +2261,7 @@ static void nfs4_xdr_enc_open_noattr(struct rpc_rqst *req,
2256 encode_sequence(xdr, &args->seq_args, &hdr); 2261 encode_sequence(xdr, &args->seq_args, &hdr);
2257 encode_putfh(xdr, args->fh, &hdr); 2262 encode_putfh(xdr, args->fh, &hdr);
2258 encode_open(xdr, args, &hdr); 2263 encode_open(xdr, args, &hdr);
2264 encode_access(xdr, args->access, &hdr);
2259 encode_getfattr(xdr, args->bitmask, &hdr); 2265 encode_getfattr(xdr, args->bitmask, &hdr);
2260 encode_nops(&hdr); 2266 encode_nops(&hdr);
2261} 2267}
@@ -4099,7 +4105,7 @@ out_overflow:
4099 return -EIO; 4105 return -EIO;
4100} 4106}
4101 4107
4102static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access) 4108static int decode_access(struct xdr_stream *xdr, u32 *supported, u32 *access)
4103{ 4109{
4104 __be32 *p; 4110 __be32 *p;
4105 uint32_t supp, acc; 4111 uint32_t supp, acc;
@@ -4113,8 +4119,8 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
4113 goto out_overflow; 4119 goto out_overflow;
4114 supp = be32_to_cpup(p++); 4120 supp = be32_to_cpup(p++);
4115 acc = be32_to_cpup(p); 4121 acc = be32_to_cpup(p);
4116 access->supported = supp; 4122 *supported = supp;
4117 access->access = acc; 4123 *access = acc;
4118 return 0; 4124 return 0;
4119out_overflow: 4125out_overflow:
4120 print_overflow_msg(__func__, xdr); 4126 print_overflow_msg(__func__, xdr);
@@ -5892,7 +5898,7 @@ static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
5892 status = decode_putfh(xdr); 5898 status = decode_putfh(xdr);
5893 if (status != 0) 5899 if (status != 0)
5894 goto out; 5900 goto out;
5895 status = decode_access(xdr, res); 5901 status = decode_access(xdr, &res->supported, &res->access);
5896 if (status != 0) 5902 if (status != 0)
5897 goto out; 5903 goto out;
5898 decode_getfattr(xdr, res->fattr, res->server); 5904 decode_getfattr(xdr, res->fattr, res->server);
@@ -6233,6 +6239,7 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
6233 status = decode_getfh(xdr, &res->fh); 6239 status = decode_getfh(xdr, &res->fh);
6234 if (status) 6240 if (status)
6235 goto out; 6241 goto out;
6242 decode_access(xdr, &res->access_supported, &res->access_result);
6236 decode_getfattr(xdr, res->f_attr, res->server); 6243 decode_getfattr(xdr, res->f_attr, res->server);
6237out: 6244out:
6238 return status; 6245 return status;
@@ -6281,6 +6288,7 @@ static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp,
6281 status = decode_open(xdr, res); 6288 status = decode_open(xdr, res);
6282 if (status) 6289 if (status)
6283 goto out; 6290 goto out;
6291 decode_access(xdr, &res->access_supported, &res->access_result);
6284 decode_getfattr(xdr, res->f_attr, res->server); 6292 decode_getfattr(xdr, res->f_attr, res->server);
6285out: 6293out:
6286 return status; 6294 return status;
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 383f3313f053..334a2f5f6bf1 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -360,6 +360,8 @@ extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
360extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); 360extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr);
361extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); 361extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr);
362extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); 362extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
363extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
364extern void nfs_access_set_mask(struct nfs_access_entry *, u32);
363extern int nfs_permission(struct inode *, int); 365extern int nfs_permission(struct inode *, int);
364extern int nfs_open(struct inode *, struct file *); 366extern int nfs_open(struct inode *, struct file *);
365extern int nfs_release(struct inode *, struct file *); 367extern int nfs_release(struct inode *, struct file *);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 5da789fdf25b..655490dae953 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -334,6 +334,7 @@ struct nfs_openargs {
334 struct nfs_seqid * seqid; 334 struct nfs_seqid * seqid;
335 int open_flags; 335 int open_flags;
336 fmode_t fmode; 336 fmode_t fmode;
337 u32 access;
337 __u64 clientid; 338 __u64 clientid;
338 struct stateowner_id id; 339 struct stateowner_id id;
339 union { 340 union {
@@ -368,6 +369,8 @@ struct nfs_openres {
368 struct nfs4_string *owner; 369 struct nfs4_string *owner;
369 struct nfs4_string *group_owner; 370 struct nfs4_string *group_owner;
370 struct nfs4_sequence_res seq_res; 371 struct nfs4_sequence_res seq_res;
372 __u32 access_supported;
373 __u32 access_result;
371}; 374};
372 375
373/* 376/*