From 5aca284210ce827f780ea2f4f9c6ab8d6e2d6648 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Mon, 1 Jul 2019 08:25:34 -0700 Subject: vfs: create a generic checking and prep function for FS_IOC_SETFLAGS Create a generic function to check incoming FS_IOC_SETFLAGS flag values and later prepare the inode for updates so that we can standardize the implementations that follow ext4's flag values. Note that the efivarfs implementation no longer fails a no-op SETFLAGS without CAP_LINUX_IMMUTABLE since that's the behavior in ext*. Signed-off-by: Darrick J. Wong Reviewed-by: Jan Kara Reviewed-by: Christoph Hellwig Acked-by: David Sterba Reviewed-by: Bob Peterson --- fs/efivarfs/file.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'fs/efivarfs') diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index 8e568428c88b..a3cc10b1bfe1 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@ -110,16 +110,22 @@ out_free: return size; } -static int -efivarfs_ioc_getxflags(struct file *file, void __user *arg) +static inline unsigned int efivarfs_getflags(struct inode *inode) { - struct inode *inode = file->f_mapping->host; unsigned int i_flags; unsigned int flags = 0; i_flags = inode->i_flags; if (i_flags & S_IMMUTABLE) flags |= FS_IMMUTABLE_FL; + return flags; +} + +static int +efivarfs_ioc_getxflags(struct file *file, void __user *arg) +{ + struct inode *inode = file->f_mapping->host; + unsigned int flags = efivarfs_getflags(inode); if (copy_to_user(arg, &flags, sizeof(flags))) return -EFAULT; @@ -132,6 +138,7 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg) struct inode *inode = file->f_mapping->host; unsigned int flags; unsigned int i_flags = 0; + unsigned int oldflags = efivarfs_getflags(inode); int error; if (!inode_owner_or_capable(inode)) @@ -143,9 +150,6 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg) if (flags & ~FS_IMMUTABLE_FL) return -EOPNOTSUPP; - if (!capable(CAP_LINUX_IMMUTABLE)) - return -EPERM; - if (flags & FS_IMMUTABLE_FL) i_flags |= S_IMMUTABLE; @@ -155,12 +159,16 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg) return error; inode_lock(inode); + + error = vfs_ioc_setflags_prepare(inode, oldflags, flags); + if (error) + goto out; + inode_set_flags(inode, i_flags, S_IMMUTABLE); +out: inode_unlock(inode); - mnt_drop_write_file(file); - - return 0; + return error; } static long -- cgit