The patch titled Subject: vfs: allow dedupe of user owned read-only files has been removed from the -mm tree. Its filename was vfs-allow-dedupe-of-user-owned-read-only-files.patch This patch was dropped because it was merged into mainline or a subsystem tree ------------------------------------------------------ From: Mark Fasheh <mfasheh@xxxxxxx> Subject: vfs: allow dedupe of user owned read-only files Patch series "vfs: fix dedupe permission check", v6. The following patches fix a couple of issues with the permission check we do in vfs_dedupe_file_range(). The first patch expands our check to allow dedupe of a file if the user owns it or otherwise would be allowed to write to it. Current behavior is that we'll allow dedupe only if: - the user is an admin (root) - the user has the file open for write This makes it impossible for a user to dedupe their own file set unless they do it as root, or ensure that all files have write permission. There's a couple of duperemove bugs open for this: https://github.com/markfasheh/duperemove/issues/129 https://github.com/markfasheh/duperemove/issues/86 The other problem we have is also related to forcing the user to open target files for write - A process trying to exec a file currently being deduped gets ETXTBUSY. The answer (as above) is to allow them to open the targets ro - root can already do this. There was a patch from Adam Borowski to fix this back in 2016: https://lkml.org/lkml/2016/7/17/130 which I have incorporated into my changes. The 2nd patch fixes our return code for permission denied to be EPERM. For some reason we're returning EINVAL - I think that's probably my fault. At any rate, we need to be returning something descriptive of the actual problem, otherwise callers see EINVAL and can't really make a valid determination of what's gone wrong. This has also popped up in duperemove, mostly in the form of cryptic error messages. Because this is a code returned to userspace, I did check the other users of extent-same that I could find. Both 'bees' and 'rust-btrfs' do the same as duperemove and simply report the error (as they should). One way I tested these patches was to make non-root owned files with read-only permissions and see if I could dedupe them as the owning user. For example, the following script fails on an unpatched kernel and succeeds with the patches applied. TESTDIR=/btrfs USER=mfasheh rm -f $TESTDIR/file* dd if=/dev/zero of=$TESTDIR/file1 count=1024 bs=1024 dd if=/dev/zero of=$TESTDIR/file2 count=1024 bs=1024 chown $USER $TESTDIR/file* chmod 444 $TESTDIR/file* # open file* for read and dedupe sudo -u $USER duperemove -Ad $TESTDIR/file* Lastly, I have an update to the fi_deduperange manpage to reflect these changes. This patch (of 2): The permission check in vfs_dedupe_file_range_one() is too coarse - We only allow dedupe of the destination file if the user is root, or they have the file open for write. This effectively limits a non-root user from deduping their own read-only files. In addition, the write file descriptor that the user is forced to hold open can prevent execution of files. As file data during a dedupe does not change, the behavior is unexpected and this has caused a number of issue reports. For an example, see: https://github.com/markfasheh/duperemove/issues/129 So change the check so we allow dedupe on the target if: - the root or admin is asking for it - the process has write access - the owner of the file is asking for the dedupe - the process could get write access That way users can open read-only and still get dedupe. Link: http://lkml.kernel.org/r/20180910232118.14424-2-mfasheh@xxxxxxx Signed-off-by: Mark Fasheh <mfasheh@xxxxxxx> Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx> Cc: Darrick J. Wong <darrick.wong@xxxxxxxxxx> Cc: David Sterba <dsterba@xxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- fs/read_write.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) --- a/fs/read_write.c~vfs-allow-dedupe-of-user-owned-read-only-files +++ a/fs/read_write.c @@ -1977,6 +1977,20 @@ out_error: } EXPORT_SYMBOL(vfs_dedupe_file_range_compare); +/* 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) { @@ -1991,7 +2005,7 @@ int vfs_dedupe_file_range_one(struct fil goto out_drop_write; ret = -EINVAL; - if (!(capable(CAP_SYS_ADMIN) || (dst_file->f_mode & FMODE_WRITE))) + if (!allow_file_dedupe(dst_file)) goto out_drop_write; ret = -EXDEV; _ Patches currently in -mm which might be from mfasheh@xxxxxxx are