From patchwork Tue Sep 29 07:28:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiao Yang X-Patchwork-Id: 11805141 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 91409139A for ; Tue, 29 Sep 2020 07:47:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7D0542075E for ; Tue, 29 Sep 2020 07:47:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725776AbgI2Hrh (ORCPT ); Tue, 29 Sep 2020 03:47:37 -0400 Received: from mail.cn.fujitsu.com ([183.91.158.132]:16796 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725535AbgI2Hrh (ORCPT ); Tue, 29 Sep 2020 03:47:37 -0400 X-IronPort-AV: E=Sophos;i="5.77,317,1596470400"; d="scan'208";a="99706518" Received: from unknown (HELO cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 29 Sep 2020 15:47:32 +0800 Received: from G08CNEXMBPEKD05.g08.fujitsu.local (unknown [10.167.33.204]) by cn.fujitsu.com (Postfix) with ESMTP id 0389048990E8; Tue, 29 Sep 2020 15:47:27 +0800 (CST) Received: from G08CNEXCHPEKD06.g08.fujitsu.local (10.167.33.205) by G08CNEXMBPEKD05.g08.fujitsu.local (10.167.33.204) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Tue, 29 Sep 2020 15:47:26 +0800 Received: from Fedora-31.g08.fujitsu.local (10.167.220.31) by G08CNEXCHPEKD06.g08.fujitsu.local (10.167.33.205) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Tue, 29 Sep 2020 15:47:23 +0800 From: Xiao Yang To: CC: , , , , , Xiao Yang Subject: [PATCH v2 1/2] ovl: support [S|G]ETFLAGS and FS[S|G]ETXATTR ioctls for directories Date: Tue, 29 Sep 2020 15:28:47 +0800 Message-ID: <20200929072848.853877-1-yangx.jy@cn.fujitsu.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-yoursite-MailScanner-ID: 0389048990E8.AC791 X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: yangx.jy@cn.fujitsu.com X-Spam-Status: No Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Amir Goldstein [S|G]ETFLAGS and FS[S|G]ETXATTR ioctls are applicable to both files and directories, so add ioctl operations to dir as well. We teach ovl_real_fdget() to get the realfile of directories which use a different type of file->private_data. ifdef away compat ioctl implementation to conform to standard practice. With this change, xfstest generic/079 which tests these ioctls on files and directories passes. Signed-off-by: Amir Goldstein Signed-off-by: Xiao Yang Reviewed-by: Xiao Yang --- V1->v2: 1) Rename subject 2) Rebase on top of the following branch: git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git overlayfs-next fs/overlayfs/file.c | 16 +++++++++++++--- fs/overlayfs/overlayfs.h | 3 +++ fs/overlayfs/readdir.c | 33 ++++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 3582c3ae819c..90b9aaebdf57 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -136,6 +136,13 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real, static int ovl_real_fdget(const struct file *file, struct fd *real) { + if (d_is_dir(file_dentry(file))) { + real->flags = 0; + real->file = ovl_dir_real_file(file, false); + + return PTR_ERR_OR_ZERO(real->file); + } + return ovl_real_fdget_meta(file, real, false); } @@ -648,7 +655,7 @@ static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, ovl_fsxflags_to_iflags(fa.fsx_xflags)); } -static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; @@ -673,8 +680,8 @@ static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return ret; } -static long ovl_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +#ifdef CONFIG_COMPAT +long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case FS_IOC32_GETFLAGS: @@ -691,6 +698,7 @@ static long ovl_compat_ioctl(struct file *file, unsigned int cmd, return ovl_ioctl(file, cmd, arg); } +#endif enum ovl_copyop { OVL_COPY, @@ -792,7 +800,9 @@ const struct file_operations ovl_file_operations = { .fallocate = ovl_fallocate, .fadvise = ovl_fadvise, .unlocked_ioctl = ovl_ioctl, +#ifdef CONFIG_COMPAT .compat_ioctl = ovl_compat_ioctl, +#endif .splice_read = ovl_splice_read, .splice_write = ovl_splice_write, diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 7bce2469fe55..f8880aa2ba0e 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -416,6 +416,7 @@ static inline int ovl_verify_upper(struct ovl_fs *ofs, struct dentry *index, /* readdir.c */ extern const struct file_operations ovl_dir_operations; +struct file *ovl_dir_real_file(const struct file *file, bool want_upper); int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list); void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list); void ovl_cache_free(struct list_head *list); @@ -503,6 +504,8 @@ struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr); extern const struct file_operations ovl_file_operations; int __init ovl_aio_request_cache_init(void); void ovl_aio_request_cache_destroy(void); +long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); /* copy_up.c */ int ovl_copy_up(struct dentry *dentry); diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 596002054ac6..392efbbe9242 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c @@ -853,16 +853,22 @@ static struct file *ovl_dir_open_realfile(struct file *file, return res; } -static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, - int datasync) +/* + * Like ovl_real_fdget(), returns upperfile if dir was copied up since open. + * Unlike ovl_real_fdget(), this caches upperfile in file->private_data. + * + * TODO: use same abstract type for file->private_data of dir and file so + * upperfile could also be cached for files as well. + */ +struct file *ovl_dir_real_file(const struct file *file, bool want_upper) { + struct ovl_dir_file *od = file->private_data; struct dentry *dentry = file->f_path.dentry; struct file *realfile = od->realfile; - /* Nothing to sync for lower */ if (!OVL_TYPE_UPPER(ovl_path_type(dentry))) - return 0; + return want_upper ? NULL : realfile; if (!ovl_should_sync(OVL_FS(dentry->d_sb))) return 0; @@ -884,7 +890,7 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, if (!od->upperfile) { if (IS_ERR(realfile)) { inode_unlock(inode); - return PTR_ERR(realfile); + return realfile; } smp_store_release(&od->upperfile, realfile); } else { @@ -897,6 +903,19 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, } } + return realfile; +} + +static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, + int datasync) +{ + struct file *realfile = ovl_dir_real_file(file, true); + int err = PTR_ERR_OR_ZERO(realfile); + + /* Nothing to sync for lower */ + if (!realfile || err) + return err; + return vfs_fsync_range(realfile, start, end, datasync); } @@ -949,6 +968,10 @@ const struct file_operations ovl_dir_operations = { .llseek = ovl_dir_llseek, .fsync = ovl_dir_fsync, .release = ovl_dir_release, + .unlocked_ioctl = ovl_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ovl_compat_ioctl, +#endif }; int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) From patchwork Tue Sep 29 07:28:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiao Yang X-Patchwork-Id: 11805143 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6DCDD6CB for ; Tue, 29 Sep 2020 07:47:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5F48C20936 for ; Tue, 29 Sep 2020 07:47:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727522AbgI2Hrj (ORCPT ); Tue, 29 Sep 2020 03:47:39 -0400 Received: from mail.cn.fujitsu.com ([183.91.158.132]:16796 "EHLO heian.cn.fujitsu.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725535AbgI2Hri (ORCPT ); Tue, 29 Sep 2020 03:47:38 -0400 X-IronPort-AV: E=Sophos;i="5.77,317,1596470400"; d="scan'208";a="99706516" Received: from unknown (HELO cn.fujitsu.com) ([10.167.33.5]) by heian.cn.fujitsu.com with ESMTP; 29 Sep 2020 15:47:32 +0800 Received: from G08CNEXMBPEKD06.g08.fujitsu.local (unknown [10.167.33.206]) by cn.fujitsu.com (Postfix) with ESMTP id C06AF48990F6; Tue, 29 Sep 2020 15:47:28 +0800 (CST) Received: from G08CNEXCHPEKD06.g08.fujitsu.local (10.167.33.205) by G08CNEXMBPEKD06.g08.fujitsu.local (10.167.33.206) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Tue, 29 Sep 2020 15:47:25 +0800 Received: from Fedora-31.g08.fujitsu.local (10.167.220.31) by G08CNEXCHPEKD06.g08.fujitsu.local (10.167.33.205) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Tue, 29 Sep 2020 15:47:25 +0800 From: Xiao Yang To: CC: , , , , , Xiao Yang Subject: [PATCH v2 2/2] ovl: use generic vfs_ioc_setflags_prepare() helper Date: Tue, 29 Sep 2020 15:28:48 +0800 Message-ID: <20200929072848.853877-2-yangx.jy@cn.fujitsu.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200929072848.853877-1-yangx.jy@cn.fujitsu.com> References: <20200929072848.853877-1-yangx.jy@cn.fujitsu.com> MIME-Version: 1.0 X-yoursite-MailScanner-ID: C06AF48990F6.ABAE1 X-yoursite-MailScanner: Found to be clean X-yoursite-MailScanner-From: yangx.jy@cn.fujitsu.com X-Spam-Status: No Precedence: bulk List-ID: X-Mailing-List: fstests@vger.kernel.org From: Amir Goldstein Canonalize to ioctl FS_* flags instead of inode S_* flags. Note that we do not call the helper vfs_ioc_fssetxattr_check() for FS_IOC_FSSETXATTR ioctl. The reason is that underlying filesystem will perform all the checks. We only need to perform the capability check before overriding credentials. Signed-off-by: Amir Goldstein Signed-off-by: Xiao Yang Reviewed-by: Xiao Yang --- V1->v2: 1) Rebase on top of the following branch: git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git overlayfs-nex fs/overlayfs/file.c | 62 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 90b9aaebdf57..7f82c9fc9d9a 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -559,12 +559,28 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd, return ret; } +static unsigned int ovl_iflags_to_fsflags(unsigned int iflags) +{ + unsigned int flags = 0; + + if (iflags & S_SYNC) + flags |= FS_SYNC_FL; + if (iflags & S_APPEND) + flags |= FS_APPEND_FL; + if (iflags & S_IMMUTABLE) + flags |= FS_IMMUTABLE_FL; + if (iflags & S_NOATIME) + flags |= FS_NOATIME_FL; + + return flags; +} + static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, - unsigned long arg, unsigned int iflags) + unsigned long arg, unsigned int flags) { long ret; struct inode *inode = file_inode(file); - unsigned int old_iflags; + unsigned int oldflags; if (!inode_owner_or_capable(inode)) return -EACCES; @@ -576,10 +592,9 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, inode_lock(inode); /* Check the capability before cred override */ - ret = -EPERM; - old_iflags = READ_ONCE(inode->i_flags); - if (((iflags ^ old_iflags) & (S_APPEND | S_IMMUTABLE)) && - !capable(CAP_LINUX_IMMUTABLE)) + oldflags = ovl_iflags_to_fsflags(READ_ONCE(inode->i_flags)); + ret = vfs_ioc_setflags_prepare(inode, oldflags, flags); + if (ret) goto unlock; ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY); @@ -598,22 +613,6 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd, } -static unsigned int ovl_fsflags_to_iflags(unsigned int flags) -{ - unsigned int iflags = 0; - - if (flags & FS_SYNC_FL) - iflags |= S_SYNC; - if (flags & FS_APPEND_FL) - iflags |= S_APPEND; - if (flags & FS_IMMUTABLE_FL) - iflags |= S_IMMUTABLE; - if (flags & FS_NOATIME_FL) - iflags |= S_NOATIME; - - return iflags; -} - static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd, unsigned long arg) { @@ -622,24 +621,23 @@ static long ovl_ioctl_set_fsflags(struct file *file, unsigned int cmd, if (get_user(flags, (int __user *) arg)) return -EFAULT; - return ovl_ioctl_set_flags(file, cmd, arg, - ovl_fsflags_to_iflags(flags)); + return ovl_ioctl_set_flags(file, cmd, arg, flags); } -static unsigned int ovl_fsxflags_to_iflags(unsigned int xflags) +static unsigned int ovl_fsxflags_to_fsflags(unsigned int xflags) { - unsigned int iflags = 0; + unsigned int flags = 0; if (xflags & FS_XFLAG_SYNC) - iflags |= S_SYNC; + flags |= FS_SYNC_FL; if (xflags & FS_XFLAG_APPEND) - iflags |= S_APPEND; + flags |= FS_APPEND_FL; if (xflags & FS_XFLAG_IMMUTABLE) - iflags |= S_IMMUTABLE; + flags |= FS_IMMUTABLE_FL; if (xflags & FS_XFLAG_NOATIME) - iflags |= S_NOATIME; + flags |= FS_NOATIME_FL; - return iflags; + return flags; } static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, @@ -652,7 +650,7 @@ static long ovl_ioctl_set_fsxflags(struct file *file, unsigned int cmd, return -EFAULT; return ovl_ioctl_set_flags(file, cmd, arg, - ovl_fsxflags_to_iflags(fa.fsx_xflags)); + ovl_fsxflags_to_fsflags(fa.fsx_xflags)); } long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)