path: root/fs/read_write.c
diff options
authorLinus Torvalds <torvalds@linux-foundation.org>2018-11-01 20:19:49 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-11-01 20:19:49 -0700
commit8adcc59974b8a65b7eac7d503364837c297139bc (patch)
tree4ab2a60bb6d058e5b18d175fc4c97c9c05f13185 /fs/read_write.c
parentMerge branch 'work.afs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs (diff)
parentfs/exofs: only use true/false for asignment of bool type variable (diff)
Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull misc vfs updates from Al Viro: "No common topic, really - a handful of assorted stuff; the least trivial bits are Mark's dedupe patches" * 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: fs/exofs: only use true/false for asignment of bool type variable fs/exofs: fix potential memory leak in mount option parsing Delete invalid assignment statements in do_sendfile iomap: remove duplicated include from iomap.c vfs: dedupe should return EPERM if permission is not granted vfs: allow dedupe of user owned read-only files ntfs: don't open-code ERR_CAST ext4: don't open-code ERR_CAST
Diffstat (limited to 'fs/read_write.c')
1 files changed, 16 insertions, 3 deletions
diff --git a/fs/read_write.c b/fs/read_write.c
index 603794b207eb..5a2ee488c5d2 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -1407,7 +1407,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
goto fput_in;
if (!(out.file->f_mode & FMODE_WRITE))
goto fput_out;
- retval = -EINVAL;
in_inode = file_inode(in.file);
out_inode = file_inode(out.file);
out_pos = out.file->f_pos;
@@ -1977,6 +1976,20 @@ out_error:
+/* Check whether we are allowed to dedupe the destination file */
+static bool allow_file_dedupe(struct file *file)
+ if (capable(CAP_SYS_ADMIN))
+ return true;
+ if (file->f_mode & FMODE_WRITE)
+ return true;
+ if (uid_eq(current_fsuid(), file_inode(file)->i_uid))
+ return true;
+ if (!inode_permission(file_inode(file), MAY_WRITE))
+ return true;
+ return false;
int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
struct file *dst_file, loff_t dst_pos, u64 len)
@@ -1990,8 +2003,8 @@ int vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
if (ret < 0)
goto out_drop_write;
- ret = -EINVAL;
- if (!(capable(CAP_SYS_ADMIN) || (dst_file->f_mode & FMODE_WRITE)))
+ ret = -EPERM;
+ if (!allow_file_dedupe(dst_file))
goto out_drop_write;
ret = -EXDEV;