diff options
author | Robbie Ko <robbieko@synology.com> | 2018-08-21 16:17:40 +0800 |
---|---|---|
committer | Tyler Hicks <tyhicks@canonical.com> | 2019-02-16 23:18:57 +0000 |
commit | d43388dea04b18f516bd7c837d9222fe7309b12d (patch) | |
tree | 49ecee9a2b01849ef2cd7d8bb340a6311969f54a /fs/ecryptfs/crypto.c | |
parent | 4b47a8b51e7bc0bcd1fa8e546a6333a04ab760d8 (diff) |
eCryptfs: fix permission denied with ecryptfs_xattr mount option when create readonly file
When the ecryptfs_xattr mount option is turned on, the ecryptfs
metadata will be written to xattr via vfs_setxattr, which will
check the WRITE permissions.
However, this will cause denial of permission when creating a
file withoug write permission.
So fix this by calling __vfs_setxattr directly to skip permission
check.
Signed-off-by: Robbie Ko <robbieko@synology.com>
[tyhicks: Copy up lower inode attributes when successful]
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Diffstat (limited to 'fs/ecryptfs/crypto.c')
-rw-r--r-- | fs/ecryptfs/crypto.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 708f931c36f1..bc2376726090 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -37,6 +37,7 @@ #include <linux/slab.h> #include <asm/unaligned.h> #include <linux/kernel.h> +#include <linux/xattr.h> #include "ecryptfs_kernel.h" #define DECRYPT 0 @@ -1131,9 +1132,21 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, char *page_virt, size_t size) { int rc; + struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + struct inode *lower_inode = d_inode(lower_dentry); - rc = ecryptfs_setxattr(ecryptfs_dentry, ecryptfs_inode, - ECRYPTFS_XATTR_NAME, page_virt, size, 0); + if (!(lower_inode->i_opflags & IOP_XATTR)) { + rc = -EOPNOTSUPP; + goto out; + } + + inode_lock(lower_inode); + rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME, + page_virt, size, 0); + if (!rc && ecryptfs_inode) + fsstack_copy_attr_all(ecryptfs_inode, lower_inode); + inode_unlock(lower_inode); +out: return rc; } |