| From ad5cd4f4ee4d5fcdb1bfb7a0c073072961e70783 Mon Sep 17 00:00:00 2001 |
| From: "Darrick J. Wong" <djwong@kernel.org> |
| Date: Tue, 8 Mar 2022 10:50:43 -0800 |
| Subject: ext4: fix fallocate to use file_modified to update permissions consistently |
| |
| From: Darrick J. Wong <djwong@kernel.org> |
| |
| commit ad5cd4f4ee4d5fcdb1bfb7a0c073072961e70783 upstream. |
| |
| Since the initial introduction of (posix) fallocate back at the turn of |
| the century, it has been possible to use this syscall to change the |
| user-visible contents of files. This can happen by extending the file |
| size during a preallocation, or through any of the newer modes (punch, |
| zero, collapse, insert range). Because the call can be used to change |
| file contents, we should treat it like we do any other modification to a |
| file -- update the mtime, and drop set[ug]id privileges/capabilities. |
| |
| The VFS function file_modified() does all this for us if pass it a |
| locked inode, so let's make fallocate drop permissions correctly. |
| |
| Signed-off-by: Darrick J. Wong <djwong@kernel.org> |
| Link: https://lore.kernel.org/r/20220308185043.GA117678@magnolia |
| Signed-off-by: Theodore Ts'o <tytso@mit.edu> |
| Cc: stable@kernel.org |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/ext4/ext4.h | 2 +- |
| fs/ext4/extents.c | 32 +++++++++++++++++++++++++------- |
| fs/ext4/inode.c | 7 ++++++- |
| 3 files changed, 32 insertions(+), 9 deletions(-) |
| |
| --- a/fs/ext4/ext4.h |
| +++ b/fs/ext4/ext4.h |
| @@ -2870,7 +2870,7 @@ extern int ext4_inode_attach_jinode(stru |
| extern int ext4_can_truncate(struct inode *inode); |
| extern int ext4_truncate(struct inode *); |
| extern int ext4_break_layouts(struct inode *); |
| -extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length); |
| +extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length); |
| extern void ext4_set_inode_flags(struct inode *, bool init); |
| extern int ext4_alloc_da_blocks(struct inode *inode); |
| extern void ext4_set_aops(struct inode *inode); |
| --- a/fs/ext4/extents.c |
| +++ b/fs/ext4/extents.c |
| @@ -4498,9 +4498,9 @@ retry: |
| return ret > 0 ? ret2 : ret; |
| } |
| |
| -static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len); |
| +static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len); |
| |
| -static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len); |
| +static int ext4_insert_range(struct file *file, loff_t offset, loff_t len); |
| |
| static long ext4_zero_range(struct file *file, loff_t offset, |
| loff_t len, int mode) |
| @@ -4571,6 +4571,10 @@ static long ext4_zero_range(struct file |
| /* Wait all existing dio workers, newcomers will block on i_mutex */ |
| inode_dio_wait(inode); |
| |
| + ret = file_modified(file); |
| + if (ret) |
| + goto out_mutex; |
| + |
| /* Preallocate the range including the unaligned edges */ |
| if (partial_begin || partial_end) { |
| ret = ext4_alloc_file_blocks(file, |
| @@ -4689,7 +4693,7 @@ long ext4_fallocate(struct file *file, i |
| ext4_fc_start_update(inode); |
| |
| if (mode & FALLOC_FL_PUNCH_HOLE) { |
| - ret = ext4_punch_hole(inode, offset, len); |
| + ret = ext4_punch_hole(file, offset, len); |
| goto exit; |
| } |
| |
| @@ -4698,12 +4702,12 @@ long ext4_fallocate(struct file *file, i |
| goto exit; |
| |
| if (mode & FALLOC_FL_COLLAPSE_RANGE) { |
| - ret = ext4_collapse_range(inode, offset, len); |
| + ret = ext4_collapse_range(file, offset, len); |
| goto exit; |
| } |
| |
| if (mode & FALLOC_FL_INSERT_RANGE) { |
| - ret = ext4_insert_range(inode, offset, len); |
| + ret = ext4_insert_range(file, offset, len); |
| goto exit; |
| } |
| |
| @@ -4739,6 +4743,10 @@ long ext4_fallocate(struct file *file, i |
| /* Wait all existing dio workers, newcomers will block on i_mutex */ |
| inode_dio_wait(inode); |
| |
| + ret = file_modified(file); |
| + if (ret) |
| + goto out; |
| + |
| ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags); |
| if (ret) |
| goto out; |
| @@ -5241,8 +5249,9 @@ out: |
| * This implements the fallocate's collapse range functionality for ext4 |
| * Returns: 0 and non-zero on error. |
| */ |
| -static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) |
| +static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len) |
| { |
| + struct inode *inode = file_inode(file); |
| struct super_block *sb = inode->i_sb; |
| ext4_lblk_t punch_start, punch_stop; |
| handle_t *handle; |
| @@ -5293,6 +5302,10 @@ static int ext4_collapse_range(struct in |
| /* Wait for existing dio to complete */ |
| inode_dio_wait(inode); |
| |
| + ret = file_modified(file); |
| + if (ret) |
| + goto out_mutex; |
| + |
| /* |
| * Prevent page faults from reinstantiating pages we have released from |
| * page cache. |
| @@ -5387,8 +5400,9 @@ out_mutex: |
| * by len bytes. |
| * Returns 0 on success, error otherwise. |
| */ |
| -static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) |
| +static int ext4_insert_range(struct file *file, loff_t offset, loff_t len) |
| { |
| + struct inode *inode = file_inode(file); |
| struct super_block *sb = inode->i_sb; |
| handle_t *handle; |
| struct ext4_ext_path *path; |
| @@ -5444,6 +5458,10 @@ static int ext4_insert_range(struct inod |
| /* Wait for existing dio to complete */ |
| inode_dio_wait(inode); |
| |
| + ret = file_modified(file); |
| + if (ret) |
| + goto out_mutex; |
| + |
| /* |
| * Prevent page faults from reinstantiating pages we have released from |
| * page cache. |
| --- a/fs/ext4/inode.c |
| +++ b/fs/ext4/inode.c |
| @@ -4028,8 +4028,9 @@ int ext4_break_layouts(struct inode *ino |
| * Returns: 0 on success or negative on failure |
| */ |
| |
| -int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) |
| +int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) |
| { |
| + struct inode *inode = file_inode(file); |
| struct super_block *sb = inode->i_sb; |
| ext4_lblk_t first_block, stop_block; |
| struct address_space *mapping = inode->i_mapping; |
| @@ -4091,6 +4092,10 @@ int ext4_punch_hole(struct inode *inode, |
| /* Wait all existing dio workers, newcomers will block on i_mutex */ |
| inode_dio_wait(inode); |
| |
| + ret = file_modified(file); |
| + if (ret) |
| + goto out_mutex; |
| + |
| /* |
| * Prevent page faults from reinstantiating pages we have released from |
| * page cache. |