Skip to content

Commit ad5cd4f

Browse files
Darrick J. Wongtytso
authored andcommitted
ext4: fix fallocate to use file_modified to update permissions consistently
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 <[email protected]> Link: https://lore.kernel.org/r/20220308185043.GA117678@magnolia Signed-off-by: Theodore Ts'o <[email protected]> Cc: [email protected]
1 parent 919adbf commit ad5cd4f

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

fs/ext4/ext4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3032,7 +3032,7 @@ extern int ext4_inode_attach_jinode(struct inode *inode);
30323032
extern int ext4_can_truncate(struct inode *inode);
30333033
extern int ext4_truncate(struct inode *);
30343034
extern int ext4_break_layouts(struct inode *);
3035-
extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);
3035+
extern int ext4_punch_hole(struct file *file, loff_t offset, loff_t length);
30363036
extern void ext4_set_inode_flags(struct inode *, bool init);
30373037
extern int ext4_alloc_da_blocks(struct inode *inode);
30383038
extern void ext4_set_aops(struct inode *inode);

fs/ext4/extents.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4500,9 +4500,9 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset,
45004500
return ret > 0 ? ret2 : ret;
45014501
}
45024502

4503-
static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len);
4503+
static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len);
45044504

4505-
static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len);
4505+
static int ext4_insert_range(struct file *file, loff_t offset, loff_t len);
45064506

45074507
static long ext4_zero_range(struct file *file, loff_t offset,
45084508
loff_t len, int mode)
@@ -4574,6 +4574,10 @@ static long ext4_zero_range(struct file *file, loff_t offset,
45744574
/* Wait all existing dio workers, newcomers will block on i_rwsem */
45754575
inode_dio_wait(inode);
45764576

4577+
ret = file_modified(file);
4578+
if (ret)
4579+
goto out_mutex;
4580+
45774581
/* Preallocate the range including the unaligned edges */
45784582
if (partial_begin || partial_end) {
45794583
ret = ext4_alloc_file_blocks(file,
@@ -4690,7 +4694,7 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
46904694
return -EOPNOTSUPP;
46914695

46924696
if (mode & FALLOC_FL_PUNCH_HOLE) {
4693-
ret = ext4_punch_hole(inode, offset, len);
4697+
ret = ext4_punch_hole(file, offset, len);
46944698
goto exit;
46954699
}
46964700

@@ -4699,12 +4703,12 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
46994703
goto exit;
47004704

47014705
if (mode & FALLOC_FL_COLLAPSE_RANGE) {
4702-
ret = ext4_collapse_range(inode, offset, len);
4706+
ret = ext4_collapse_range(file, offset, len);
47034707
goto exit;
47044708
}
47054709

47064710
if (mode & FALLOC_FL_INSERT_RANGE) {
4707-
ret = ext4_insert_range(inode, offset, len);
4711+
ret = ext4_insert_range(file, offset, len);
47084712
goto exit;
47094713
}
47104714

@@ -4740,6 +4744,10 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
47404744
/* Wait all existing dio workers, newcomers will block on i_rwsem */
47414745
inode_dio_wait(inode);
47424746

4747+
ret = file_modified(file);
4748+
if (ret)
4749+
goto out;
4750+
47434751
ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, flags);
47444752
if (ret)
47454753
goto out;
@@ -5241,8 +5249,9 @@ ext4_ext_shift_extents(struct inode *inode, handle_t *handle,
52415249
* This implements the fallocate's collapse range functionality for ext4
52425250
* Returns: 0 and non-zero on error.
52435251
*/
5244-
static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
5252+
static int ext4_collapse_range(struct file *file, loff_t offset, loff_t len)
52455253
{
5254+
struct inode *inode = file_inode(file);
52465255
struct super_block *sb = inode->i_sb;
52475256
struct address_space *mapping = inode->i_mapping;
52485257
ext4_lblk_t punch_start, punch_stop;
@@ -5294,6 +5303,10 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
52945303
/* Wait for existing dio to complete */
52955304
inode_dio_wait(inode);
52965305

5306+
ret = file_modified(file);
5307+
if (ret)
5308+
goto out_mutex;
5309+
52975310
/*
52985311
* Prevent page faults from reinstantiating pages we have released from
52995312
* page cache.
@@ -5387,8 +5400,9 @@ static int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len)
53875400
* by len bytes.
53885401
* Returns 0 on success, error otherwise.
53895402
*/
5390-
static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
5403+
static int ext4_insert_range(struct file *file, loff_t offset, loff_t len)
53915404
{
5405+
struct inode *inode = file_inode(file);
53925406
struct super_block *sb = inode->i_sb;
53935407
struct address_space *mapping = inode->i_mapping;
53945408
handle_t *handle;
@@ -5445,6 +5459,10 @@ static int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len)
54455459
/* Wait for existing dio to complete */
54465460
inode_dio_wait(inode);
54475461

5462+
ret = file_modified(file);
5463+
if (ret)
5464+
goto out_mutex;
5465+
54485466
/*
54495467
* Prevent page faults from reinstantiating pages we have released from
54505468
* page cache.

fs/ext4/inode.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3946,8 +3946,9 @@ int ext4_break_layouts(struct inode *inode)
39463946
* Returns: 0 on success or negative on failure
39473947
*/
39483948

3949-
int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
3949+
int ext4_punch_hole(struct file *file, loff_t offset, loff_t length)
39503950
{
3951+
struct inode *inode = file_inode(file);
39513952
struct super_block *sb = inode->i_sb;
39523953
ext4_lblk_t first_block, stop_block;
39533954
struct address_space *mapping = inode->i_mapping;
@@ -4009,6 +4010,10 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
40094010
/* Wait all existing dio workers, newcomers will block on i_rwsem */
40104011
inode_dio_wait(inode);
40114012

4013+
ret = file_modified(file);
4014+
if (ret)
4015+
goto out_mutex;
4016+
40124017
/*
40134018
* Prevent page faults from reinstantiating pages we have released from
40144019
* page cache.

0 commit comments

Comments
 (0)