summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-07-11 23:54:35 +0200
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2017-07-21 17:51:19 +0200
commitecbb903c56745d59c301db26dd7d8b74b520eb84 (patch)
tree882b94947ed7bae985aa9535066452a74d01d404 /fs
parentNFS: Store the raw NFS access mask in the inode's access cache (diff)
downloadlinux-ecbb903c56745d59c301db26dd7d8b74b520eb84.tar.xz
linux-ecbb903c56745d59c301db26dd7d8b74b520eb84.zip
NFS: Be more careful about mapping file permissions
When mapping a directory, we want the MAY_WRITE permissions to reflect whether or not we have permission to modify, add and delete the directory entries. MAY_EXEC must map to lookup permissions. On the other hand, for files, we want MAY_WRITE to reflect a permission to modify and extend the file. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/dir.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 8fae8b00b8f5..37a6180ee2e8 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -2379,21 +2379,30 @@ EXPORT_SYMBOL_GPL(nfs_access_add_cache);
#define NFS_MAY_WRITE (NFS4_ACCESS_MODIFY | \
NFS4_ACCESS_EXTEND | \
NFS4_ACCESS_DELETE)
+#define NFS_FILE_MAY_WRITE (NFS4_ACCESS_MODIFY | \
+ NFS4_ACCESS_EXTEND)
+#define NFS_DIR_MAY_WRITE NFS_MAY_WRITE
#define NFS_MAY_LOOKUP (NFS4_ACCESS_LOOKUP)
#define NFS_MAY_EXECUTE (NFS4_ACCESS_EXECUTE)
static int
-nfs_access_calc_mask(u32 access_result)
+nfs_access_calc_mask(u32 access_result, umode_t umode)
{
int mask = 0;
if (access_result & NFS_MAY_READ)
mask |= MAY_READ;
- if (access_result & NFS_MAY_WRITE)
- mask |= MAY_WRITE;
- if (access_result & NFS_MAY_LOOKUP)
- mask |= MAY_EXEC;
- if (access_result & NFS_MAY_EXECUTE)
- mask |= MAY_EXEC;
+ if (S_ISDIR(umode)) {
+ if ((access_result & NFS_DIR_MAY_WRITE) == NFS_DIR_MAY_WRITE)
+ mask |= MAY_WRITE;
+ if ((access_result & NFS_MAY_LOOKUP) == NFS_MAY_LOOKUP)
+ mask |= MAY_EXEC;
+ } else if (S_ISREG(umode)) {
+ if ((access_result & NFS_FILE_MAY_WRITE) == NFS_FILE_MAY_WRITE)
+ mask |= MAY_WRITE;
+ if ((access_result & NFS_MAY_EXECUTE) == NFS_MAY_EXECUTE)
+ mask |= MAY_EXEC;
+ } else if (access_result & NFS_MAY_WRITE)
+ mask |= MAY_WRITE;
return mask;
}
@@ -2438,7 +2447,7 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
}
nfs_access_add_cache(inode, &cache);
out_cached:
- cache_mask = nfs_access_calc_mask(cache.mask);
+ cache_mask = nfs_access_calc_mask(cache.mask, inode->i_mode);
if ((mask & ~cache_mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
status = -EACCES;
out: