diff options
| -rw-r--r-- | fs/f2fs/file.c | 9 | ||||
| -rw-r--r-- | fs/inode.c | 24 | ||||
| -rw-r--r-- | include/linux/fs.h | 3 |
3 files changed, 35 insertions, 1 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 6a19adbf1604..08d71330d2ae 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1779,7 +1779,8 @@ static int f2fs_ioc_getflags(struct file *filp, unsigned long arg) static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); - u32 fsflags; + struct f2fs_inode_info *fi = F2FS_I(inode); + u32 fsflags, old_fsflags; u32 iflags; int ret; @@ -1803,8 +1804,14 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg) inode_lock(inode); + old_fsflags = f2fs_iflags_to_fsflags(fi->i_flags); + ret = vfs_ioc_setflags_prepare(inode, old_fsflags, fsflags); + if (ret) + goto out; + ret = f2fs_setflags_common(inode, iflags, f2fs_fsflags_to_iflags(F2FS_SETTABLE_FS_FL)); +out: inode_unlock(inode); mnt_drop_write_file(filp); return ret; diff --git a/fs/inode.c b/fs/inode.c index 9fa27369e8a2..527789e43c94 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2029,3 +2029,27 @@ void inode_set_flags(struct inode *inode, unsigned int flags, new_flags) != old_flags)); } EXPORT_SYMBOL(inode_set_flags); + +/* + * Generic function to check FS_IOC_SETFLAGS values and reject any invalid + * configurations. + * + * Note: the caller should be holding i_mutex, or else be sure that they have + * exclusive access to the inode structure. + */ +int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags, + unsigned int flags) +{ + /* + * The IMMUTABLE and APPEND_ONLY flags can only be changed by + * the relevant capability. + * + * This test looks nicer. Thanks to Pauline Middelink + */ + if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL) && + !capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + + return 0; +} +EXPORT_SYMBOL(vfs_ioc_setflags_prepare); diff --git a/include/linux/fs.h b/include/linux/fs.h index 314bf410e3ae..5bdae7cb4eb1 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3088,4 +3088,7 @@ static inline bool dir_relax(struct inode *inode) extern bool path_noexec(const struct path *path); +int vfs_ioc_setflags_prepare(struct inode *inode, unsigned int oldflags, + unsigned int flags); + #endif /* _LINUX_FS_H */ |
