Skip to content

Commit 4acf3bc

Browse files
amir73iljankara
authored andcommitted
fsnotify: generate pre-content permission event on truncate
Generate FS_PRE_ACCESS event before truncate, without sb_writers held. Move the security hooks also before sb_start_write() to conform with other security hooks (e.g. in write, fallocate). The event will have a range info of the page surrounding the new size to provide an opportunity to fill the conetnt at the end of file before truncating to non-page aligned size. Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Jan Kara <[email protected]> Link: https://patch.msgid.link/23af8201db6ac2efdea94f09ab067d81ba5de7a7.1731684329.git.josef@toxicpanda.com
1 parent 9740d17 commit 4acf3bc

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

fs/open.c

+21-10
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,18 @@ long vfs_truncate(const struct path *path, loff_t length)
8181
if (!S_ISREG(inode->i_mode))
8282
return -EINVAL;
8383

84-
error = mnt_want_write(path->mnt);
85-
if (error)
86-
goto out;
87-
8884
idmap = mnt_idmap(path->mnt);
8985
error = inode_permission(idmap, inode, MAY_WRITE);
9086
if (error)
91-
goto mnt_drop_write_and_out;
87+
return error;
88+
89+
error = fsnotify_truncate_perm(path, length);
90+
if (error)
91+
return error;
92+
93+
error = mnt_want_write(path->mnt);
94+
if (error)
95+
return error;
9296

9397
error = -EPERM;
9498
if (IS_APPEND(inode))
@@ -114,7 +118,7 @@ long vfs_truncate(const struct path *path, loff_t length)
114118
put_write_access(inode);
115119
mnt_drop_write_and_out:
116120
mnt_drop_write(path->mnt);
117-
out:
121+
118122
return error;
119123
}
120124
EXPORT_SYMBOL_GPL(vfs_truncate);
@@ -175,11 +179,18 @@ long do_ftruncate(struct file *file, loff_t length, int small)
175179
/* Check IS_APPEND on real upper inode */
176180
if (IS_APPEND(file_inode(file)))
177181
return -EPERM;
178-
sb_start_write(inode->i_sb);
182+
179183
error = security_file_truncate(file);
180-
if (!error)
181-
error = do_truncate(file_mnt_idmap(file), dentry, length,
182-
ATTR_MTIME | ATTR_CTIME, file);
184+
if (error)
185+
return error;
186+
187+
error = fsnotify_truncate_perm(&file->f_path, length);
188+
if (error)
189+
return error;
190+
191+
sb_start_write(inode->i_sb);
192+
error = do_truncate(file_mnt_idmap(file), dentry, length,
193+
ATTR_MTIME | ATTR_CTIME, file);
183194
sb_end_write(inode->i_sb);
184195

185196
return error;

include/linux/fsnotify.h

+20
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,21 @@ static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
170170
return fsnotify_path(&file->f_path, FS_ACCESS_PERM);
171171
}
172172

173+
/*
174+
* fsnotify_truncate_perm - permission hook before file truncate
175+
*/
176+
static inline int fsnotify_truncate_perm(const struct path *path, loff_t length)
177+
{
178+
struct inode *inode = d_inode(path->dentry);
179+
180+
if (!(inode->i_sb->s_iflags & SB_I_ALLOW_HSM) ||
181+
!fsnotify_sb_has_priority_watchers(inode->i_sb,
182+
FSNOTIFY_PRIO_PRE_CONTENT))
183+
return 0;
184+
185+
return fsnotify_pre_content(path, &length, 0);
186+
}
187+
173188
/*
174189
* fsnotify_file_perm - permission hook before file access (unknown range)
175190
*/
@@ -208,6 +223,11 @@ static inline int fsnotify_file_area_perm(struct file *file, int perm_mask,
208223
return 0;
209224
}
210225

226+
static inline int fsnotify_truncate_perm(const struct path *path, loff_t length)
227+
{
228+
return 0;
229+
}
230+
211231
static inline int fsnotify_file_perm(struct file *file, int perm_mask)
212232
{
213233
return 0;

0 commit comments

Comments
 (0)