[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20201128181222.GA18570@mail.hallyn.com>
Date: Sat, 28 Nov 2020 12:12:22 -0600
From: "Serge E. Hallyn" <serge@...lyn.com>
To: Christian Brauner <christian.brauner@...ntu.com>
Cc: Alexander Viro <viro@...iv.linux.org.uk>,
Christoph Hellwig <hch@...radead.org>,
linux-fsdevel@...r.kernel.org,
John Johansen <john.johansen@...onical.com>,
James Morris <jmorris@...ei.org>,
Mimi Zohar <zohar@...ux.ibm.com>,
Dmitry Kasatkin <dmitry.kasatkin@...il.com>,
Stephen Smalley <stephen.smalley.work@...il.com>,
Casey Schaufler <casey@...aufler-ca.com>,
Arnd Bergmann <arnd@...db.de>,
Andreas Dilger <adilger.kernel@...ger.ca>,
OGAWA Hirofumi <hirofumi@...l.parknet.co.jp>,
Geoffrey Thomas <geofft@...reload.com>,
Mrunal Patel <mpatel@...hat.com>,
Josh Triplett <josh@...htriplett.org>,
Andy Lutomirski <luto@...nel.org>,
Theodore Tso <tytso@....edu>, Alban Crequy <alban@...volk.io>,
Tycho Andersen <tycho@...ho.ws>,
David Howells <dhowells@...hat.com>,
James Bottomley <James.Bottomley@...senpartnership.com>,
Jann Horn <jannh@...gle.com>,
Seth Forshee <seth.forshee@...onical.com>,
Stéphane Graber <stgraber@...ntu.com>,
Aleksa Sarai <cyphar@...har.com>,
Lennart Poettering <lennart@...ttering.net>,
"Eric W. Biederman" <ebiederm@...ssion.com>, smbarber@...omium.org,
Phil Estes <estesp@...il.com>, Serge Hallyn <serge@...lyn.com>,
Kees Cook <keescook@...omium.org>,
Todd Kjos <tkjos@...gle.com>, Jonathan Corbet <corbet@....net>,
containers@...ts.linux-foundation.org,
linux-security-module@...r.kernel.org, linux-api@...r.kernel.org,
linux-ext4@...r.kernel.org, linux-audit@...hat.com,
linux-integrity@...r.kernel.org, selinux@...r.kernel.org,
Christoph Hellwig <hch@....de>
Subject: Re: [PATCH v2 10/39] inode: add idmapped mount aware init and
permission helpers
On Sun, Nov 15, 2020 at 11:36:49AM +0100, Christian Brauner wrote:
> The inode_owner_or_capable() helper determines whether the caller is the
> owner of the inode or is capable with respect to that inode. Allow it to
> handle idmapped mounts. If the inode is accessed through an idmapped mount
> we first need to map it according to the mount's user namespace.
> Afterwards the checks are identical to non-idmapped mounts. If the initial
> user namespace is passed all operations are a nop so non-idmapped mounts
> will not see a change in behavior and will not see any performance impact.
>
> Similarly, we allow the inode_init_owner() helper to handle idmapped
> mounts. It initializes a new inode on idmapped mounts by mapping the fsuid
> and fsgid of the caller from the mount's user namespace. If the initial
> user namespace is passed all operations are a nop so non-idmapped mounts
> will not see a change in behavior and will also not see any performance
> impact.
>
> Cc: Christoph Hellwig <hch@....de>
> Cc: David Howells <dhowells@...hat.com>
> Cc: Al Viro <viro@...iv.linux.org.uk>
> Cc: linux-fsdevel@...r.kernel.org
> Signed-off-by: Christian Brauner <christian.brauner@...ntu.com>
> ---
> /* v2 */
> - Christoph Hellwig:
> - Don't pollute the vfs with additional helpers simply extend the existing
> helpers with an additional argument and switch all callers.
> ---
> fs/9p/acl.c | 2 +-
> fs/9p/vfs_inode.c | 2 +-
> fs/attr.c | 6 +++---
> fs/bfs/dir.c | 2 +-
> fs/btrfs/inode.c | 2 +-
> fs/btrfs/ioctl.c | 10 +++++-----
> fs/btrfs/tests/btrfs-tests.c | 2 +-
> fs/crypto/policy.c | 2 +-
> fs/efivarfs/file.c | 2 +-
> fs/ext2/ialloc.c | 2 +-
> fs/ext2/ioctl.c | 6 +++---
> fs/ext4/ialloc.c | 2 +-
> fs/ext4/ioctl.c | 14 +++++++-------
> fs/f2fs/file.c | 14 +++++++-------
> fs/f2fs/namei.c | 2 +-
> fs/f2fs/xattr.c | 2 +-
> fs/fcntl.c | 2 +-
> fs/gfs2/file.c | 2 +-
> fs/hfsplus/inode.c | 2 +-
> fs/hfsplus/ioctl.c | 2 +-
> fs/hugetlbfs/inode.c | 2 +-
> fs/inode.c | 23 ++++++++++++++---------
> fs/jfs/ioctl.c | 2 +-
> fs/jfs/jfs_inode.c | 2 +-
> fs/minix/bitmap.c | 2 +-
> fs/namei.c | 4 ++--
> fs/nilfs2/inode.c | 2 +-
> fs/nilfs2/ioctl.c | 2 +-
> fs/ocfs2/dlmfs/dlmfs.c | 4 ++--
> fs/ocfs2/ioctl.c | 2 +-
> fs/ocfs2/namei.c | 2 +-
> fs/omfs/inode.c | 2 +-
> fs/overlayfs/dir.c | 2 +-
> fs/overlayfs/file.c | 4 ++--
> fs/overlayfs/super.c | 2 +-
> fs/overlayfs/util.c | 2 +-
> fs/posix_acl.c | 2 +-
> fs/ramfs/inode.c | 2 +-
> fs/reiserfs/ioctl.c | 4 ++--
> fs/reiserfs/namei.c | 2 +-
> fs/sysv/ialloc.c | 2 +-
> fs/ubifs/dir.c | 2 +-
> fs/ubifs/ioctl.c | 2 +-
> fs/udf/ialloc.c | 2 +-
> fs/ufs/ialloc.c | 2 +-
> fs/xattr.c | 2 +-
> fs/xfs/xfs_ioctl.c | 2 +-
> fs/zonefs/super.c | 2 +-
> include/linux/fs.h | 7 ++++---
> kernel/bpf/inode.c | 2 +-
> mm/madvise.c | 2 +-
> mm/mincore.c | 2 +-
> mm/shmem.c | 2 +-
> security/selinux/hooks.c | 4 ++--
> 54 files changed, 95 insertions(+), 89 deletions(-)
>
> diff --git a/fs/9p/acl.c b/fs/9p/acl.c
> index 6261719f6f2a..d77b28e8d57a 100644
> --- a/fs/9p/acl.c
> +++ b/fs/9p/acl.c
> @@ -258,7 +258,7 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
>
> if (S_ISLNK(inode->i_mode))
> return -EOPNOTSUPP;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
> if (value) {
> /* update the cached acl value */
> diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
> index ae0c38ad1fcb..f058e89df30f 100644
> --- a/fs/9p/vfs_inode.c
> +++ b/fs/9p/vfs_inode.c
> @@ -251,7 +251,7 @@ int v9fs_init_inode(struct v9fs_session_info *v9ses,
> {
> int err = 0;
>
> - inode_init_owner(inode, NULL, mode);
> + inode_init_owner(inode, &init_user_ns, NULL, mode);
> inode->i_blocks = 0;
> inode->i_rdev = rdev;
> inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
> diff --git a/fs/attr.c b/fs/attr.c
> index c9e29e589cec..00ae0b000146 100644
> --- a/fs/attr.c
> +++ b/fs/attr.c
> @@ -87,7 +87,7 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
>
> /* Make sure a caller can chmod. */
> if (ia_valid & ATTR_MODE) {
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
> /* Also check the setgid bit! */
> if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
> @@ -98,7 +98,7 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
>
> /* Check for setting the inode time. */
> if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
> }
>
> @@ -243,7 +243,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
> if (IS_IMMUTABLE(inode))
> return -EPERM;
>
> - if (!inode_owner_or_capable(inode)) {
> + if (!inode_owner_or_capable(&init_user_ns, inode)) {
> error = inode_permission(&init_user_ns, inode,
> MAY_WRITE);
> if (error)
> diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
> index d8dfe3a0cb39..c5ae76a87be5 100644
> --- a/fs/bfs/dir.c
> +++ b/fs/bfs/dir.c
> @@ -96,7 +96,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
> }
> set_bit(ino, info->si_imap);
> info->si_freei--;
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
> inode->i_blocks = 0;
> inode->i_op = &bfs_file_inops;
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index 32e3bf88d4f7..ed1a5bf5f068 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -6015,7 +6015,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> if (ret != 0)
> goto fail_unlock;
>
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode_set_bytes(inode, 0);
>
> inode->i_mtime = current_time(inode);
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 771ee08920ed..39f25b5d06ed 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -205,7 +205,7 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
> const char *comp = NULL;
> u32 binode_flags;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> if (btrfs_root_readonly(root))
> @@ -417,7 +417,7 @@ static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg)
> unsigned old_i_flags;
> int ret = 0;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> if (btrfs_root_readonly(root))
> @@ -1813,7 +1813,7 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file,
> btrfs_info(BTRFS_I(file_inode(file))->root->fs_info,
> "Snapshot src from another FS");
> ret = -EXDEV;
> - } else if (!inode_owner_or_capable(src_inode)) {
> + } else if (!inode_owner_or_capable(&init_user_ns, src_inode)) {
> /*
> * Subvolume creation is not restricted, but snapshots
> * are limited to own subvolumes only
> @@ -1933,7 +1933,7 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
> u64 flags;
> int ret = 0;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> ret = mnt_want_write_file(file);
> @@ -4403,7 +4403,7 @@ static long _btrfs_ioctl_set_received_subvol(struct file *file,
> int ret = 0;
> int received_uuid_changed;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> ret = mnt_want_write_file(file);
> diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
> index 999c14e5d0bd..ac8e604d44e3 100644
> --- a/fs/btrfs/tests/btrfs-tests.c
> +++ b/fs/btrfs/tests/btrfs-tests.c
> @@ -56,7 +56,7 @@ struct inode *btrfs_new_test_inode(void)
>
> inode = new_inode(test_mnt->mnt_sb);
> if (inode)
> - inode_init_owner(inode, NULL, S_IFREG);
> + inode_init_owner(inode, &init_user_ns, NULL, S_IFREG);
>
> return inode;
> }
> diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
> index 4441d9944b9e..6ddd9f0d8b36 100644
> --- a/fs/crypto/policy.c
> +++ b/fs/crypto/policy.c
> @@ -462,7 +462,7 @@ int fscrypt_ioctl_set_policy(struct file *filp, const void __user *arg)
> return -EFAULT;
> policy.version = version;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> ret = mnt_want_write_file(filp);
> diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
> index feaa5e182b7b..e6bc0302643b 100644
> --- a/fs/efivarfs/file.c
> +++ b/fs/efivarfs/file.c
> @@ -137,7 +137,7 @@ efivarfs_ioc_setxflags(struct file *file, void __user *arg)
> unsigned int oldflags = efivarfs_getflags(inode);
> int error;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (copy_from_user(&flags, arg, sizeof(flags)))
> diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
> index 432c3febea6d..5081f2dd8a20 100644
> --- a/fs/ext2/ialloc.c
> +++ b/fs/ext2/ialloc.c
> @@ -551,7 +551,7 @@ struct inode *ext2_new_inode(struct inode *dir, umode_t mode,
> inode->i_uid = current_fsuid();
> inode->i_gid = dir->i_gid;
> } else
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
>
> inode->i_ino = ino;
> inode->i_blocks = 0;
> diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
> index 32a8d10b579d..b399cbb7022d 100644
> --- a/fs/ext2/ioctl.c
> +++ b/fs/ext2/ioctl.c
> @@ -39,7 +39,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> if (ret)
> return ret;
>
> - if (!inode_owner_or_capable(inode)) {
> + if (!inode_owner_or_capable(&init_user_ns, inode)) {
> ret = -EACCES;
> goto setflags_out;
> }
> @@ -84,7 +84,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> case EXT2_IOC_SETVERSION: {
> __u32 generation;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
> ret = mnt_want_write_file(filp);
> if (ret)
> @@ -117,7 +117,7 @@ long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
> return -ENOTTY;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (get_user(rsv_window_size, (int __user *)arg))
> diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
> index b215c564bc31..d91f69282311 100644
> --- a/fs/ext4/ialloc.c
> +++ b/fs/ext4/ialloc.c
> @@ -972,7 +972,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,
> inode->i_uid = current_fsuid();
> inode->i_gid = dir->i_gid;
> } else
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
>
> if (ext4_has_feature_project(sb) &&
> ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT))
> diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
> index f0381876a7e5..e35aba820254 100644
> --- a/fs/ext4/ioctl.c
> +++ b/fs/ext4/ioctl.c
> @@ -139,7 +139,7 @@ static long swap_inode_boot_loader(struct super_block *sb,
> }
>
> if (IS_RDONLY(inode) || IS_APPEND(inode) || IS_IMMUTABLE(inode) ||
> - !inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) {
> + !inode_owner_or_capable(&init_user_ns, inode) || !capable(CAP_SYS_ADMIN)) {
> err = -EPERM;
> goto journal_err_out;
> }
> @@ -829,7 +829,7 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> case FS_IOC_SETFLAGS: {
> int err;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (get_user(flags, (int __user *) arg))
> @@ -871,7 +871,7 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> __u32 generation;
> int err;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> if (ext4_has_metadata_csum(inode->i_sb)) {
> @@ -1010,7 +1010,7 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> case EXT4_IOC_MIGRATE:
> {
> int err;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> err = mnt_want_write_file(filp);
> @@ -1032,7 +1032,7 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> case EXT4_IOC_ALLOC_DA_BLKS:
> {
> int err;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> err = mnt_want_write_file(filp);
> @@ -1214,7 +1214,7 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>
> case EXT4_IOC_CLEAR_ES_CACHE:
> {
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
> ext4_clear_inode_es(inode);
> return 0;
> @@ -1260,7 +1260,7 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> return -EFAULT;
>
> /* Make sure caller has proper permission */
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (fa.fsx_xflags & ~EXT4_SUPPORTED_FS_XFLAGS)
> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
> index ee861c6d9ff0..333442e96cc4 100644
> --- a/fs/f2fs/file.c
> +++ b/fs/f2fs/file.c
> @@ -1955,7 +1955,7 @@ static int f2fs_ioc_setflags(struct file *filp, unsigned long arg)
> u32 iflags;
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (get_user(fsflags, (int __user *)arg))
> @@ -2002,7 +2002,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
> struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (!S_ISREG(inode->i_mode))
> @@ -2069,7 +2069,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
> struct inode *inode = file_inode(filp);
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> ret = mnt_want_write_file(filp);
> @@ -2111,7 +2111,7 @@ static int f2fs_ioc_start_volatile_write(struct file *filp)
> struct inode *inode = file_inode(filp);
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (!S_ISREG(inode->i_mode))
> @@ -2146,7 +2146,7 @@ static int f2fs_ioc_release_volatile_write(struct file *filp)
> struct inode *inode = file_inode(filp);
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> ret = mnt_want_write_file(filp);
> @@ -2175,7 +2175,7 @@ static int f2fs_ioc_abort_volatile_write(struct file *filp)
> struct inode *inode = file_inode(filp);
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> ret = mnt_want_write_file(filp);
> @@ -3153,7 +3153,7 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg)
> return -EFAULT;
>
> /* Make sure caller has proper permission */
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (fa.fsx_xflags & ~F2FS_SUPPORTED_XFLAGS)
> diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
> index 8fa37d1434de..66b522e61e50 100644
> --- a/fs/f2fs/namei.c
> +++ b/fs/f2fs/namei.c
> @@ -46,7 +46,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
>
> nid_free = true;
>
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
>
> inode->i_ino = ino;
> inode->i_blocks = 0;
> diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
> index 65afcc3cc68a..d772bf13a814 100644
> --- a/fs/f2fs/xattr.c
> +++ b/fs/f2fs/xattr.c
> @@ -114,7 +114,7 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
> unsigned char old_advise = F2FS_I(inode)->i_advise;
> unsigned char new_advise;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
> if (value == NULL)
> return -EINVAL;
> diff --git a/fs/fcntl.c b/fs/fcntl.c
> index 19ac5baad50f..df091d435603 100644
> --- a/fs/fcntl.c
> +++ b/fs/fcntl.c
> @@ -46,7 +46,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
>
> /* O_NOATIME can only be set by the owner or superuser */
> if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> /* required for strict SunOS emulation */
> diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
> index b39b339feddc..1d994bdfffaa 100644
> --- a/fs/gfs2/file.c
> +++ b/fs/gfs2/file.c
> @@ -238,7 +238,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask,
> goto out;
>
> error = -EACCES;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> goto out;
>
> error = 0;
> diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
> index e3da9e96b835..02d51cbcff04 100644
> --- a/fs/hfsplus/inode.c
> +++ b/fs/hfsplus/inode.c
> @@ -376,7 +376,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, struct inode *dir,
> return NULL;
>
> inode->i_ino = sbi->next_cnid++;
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> set_nlink(inode, 1);
> inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
>
> diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
> index ce15b9496b77..3edb1926d127 100644
> --- a/fs/hfsplus/ioctl.c
> +++ b/fs/hfsplus/ioctl.c
> @@ -91,7 +91,7 @@ static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
> if (err)
> goto out;
>
> - if (!inode_owner_or_capable(inode)) {
> + if (!inode_owner_or_capable(&init_user_ns, inode)) {
> err = -EACCES;
> goto out_drop_write;
> }
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index b5c109703daa..fed6ddfc3f3a 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -836,7 +836,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
> struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode);
>
> inode->i_ino = get_next_ino();
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> lockdep_set_class(&inode->i_mapping->i_mmap_rwsem,
> &hugetlbfs_i_mmap_rwsem_key);
> inode->i_mapping->a_ops = &hugetlbfs_aops;
> diff --git a/fs/inode.c b/fs/inode.c
> index 7a15372d9c2d..d6dfa876c58d 100644
> --- a/fs/inode.c
> +++ b/fs/inode.c
> @@ -2132,13 +2132,14 @@ EXPORT_SYMBOL(init_special_inode);
> /**
> * inode_init_owner - Init uid,gid,mode for new inode according to posix standards
> * @inode: New inode
> + * @user_ns: User namespace the inode is accessed from
> * @dir: Directory inode
> * @mode: mode of the new inode
> */
> -void inode_init_owner(struct inode *inode, const struct inode *dir,
> - umode_t mode)
> +void inode_init_owner(struct inode *inode, struct user_namespace *user_ns,
> + const struct inode *dir, umode_t mode)
> {
> - inode->i_uid = current_fsuid();
> + inode->i_uid = fsuid_into_mnt(user_ns);
> if (dir && dir->i_mode & S_ISGID) {
> inode->i_gid = dir->i_gid;
>
> @@ -2146,31 +2147,35 @@ void inode_init_owner(struct inode *inode, const struct inode *dir,
> if (S_ISDIR(mode))
> mode |= S_ISGID;
> else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
> - !in_group_p(inode->i_gid) &&
> - !capable_wrt_inode_uidgid(&init_user_ns, dir, CAP_FSETID))
> + !in_group_p(i_gid_into_mnt(user_ns, inode)) &&
> + !capable_wrt_inode_uidgid(user_ns, dir, CAP_FSETID))
> mode &= ~S_ISGID;
> } else
> - inode->i_gid = current_fsgid();
> + inode->i_gid = fsgid_into_mnt(user_ns);
> inode->i_mode = mode;
> }
> EXPORT_SYMBOL(inode_init_owner);
>
> /**
> * inode_owner_or_capable - check current task permissions to inode
> + * @user_ns: User namespace the inode is accessed from
> * @inode: inode being checked
> *
> * Return true if current either has CAP_FOWNER in a namespace with the
> * inode owner uid mapped, or owns the file.
> */
> -bool inode_owner_or_capable(const struct inode *inode)
> +bool inode_owner_or_capable(struct user_namespace *user_ns,
> + const struct inode *inode)
> {
> + kuid_t i_uid;
> struct user_namespace *ns;
>
> - if (uid_eq(current_fsuid(), inode->i_uid))
> + i_uid = i_uid_into_mnt(user_ns, inode);
Is there a way to end up in a situation where current_fsuid() is
INVALID_UID? The only way I can think of is to enter a userns
which requires CAP_SYS_ADMIN to it in the first place. But actually
that suffices here. If inode->i_uid is invalid in user_ns, and
I enter my userns without setting a uid, the uid_eq() below will
pass and I'll get privilege over someone else's inode, right?
> + if (uid_eq(current_fsuid(), i_uid))
> return true;
>
> ns = current_user_ns();
> - if (kuid_has_mapping(ns, inode->i_uid) && ns_capable(ns, CAP_FOWNER))
> + if (kuid_has_mapping(ns, i_uid) && ns_capable(ns, CAP_FOWNER))
> return true;
> return false;
> }
> diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
> index 10ee0ecca1a8..2581d4db58ff 100644
> --- a/fs/jfs/ioctl.c
> +++ b/fs/jfs/ioctl.c
> @@ -76,7 +76,7 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> if (err)
> return err;
>
> - if (!inode_owner_or_capable(inode)) {
> + if (!inode_owner_or_capable(&init_user_ns, inode)) {
> err = -EACCES;
> goto setflags_out;
> }
> diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
> index 4cef170630db..282a785bbf29 100644
> --- a/fs/jfs/jfs_inode.c
> +++ b/fs/jfs/jfs_inode.c
> @@ -64,7 +64,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
> goto fail_put;
> }
>
> - inode_init_owner(inode, parent, mode);
> + inode_init_owner(inode, &init_user_ns, parent, mode);
> /*
> * New inodes need to save sane values on disk when
> * uid & gid mount options are used
> diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
> index f4e5e5181a14..d99a78c83fbc 100644
> --- a/fs/minix/bitmap.c
> +++ b/fs/minix/bitmap.c
> @@ -252,7 +252,7 @@ struct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error)
> iput(inode);
> return NULL;
> }
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_ino = j;
> inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
> inode->i_blocks = 0;
> diff --git a/fs/namei.c b/fs/namei.c
> index 38222f92efb6..35952c28ee29 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -1047,7 +1047,7 @@ int may_linkat(struct path *link)
> /* Source inode owner (or CAP_FOWNER) can hardlink all they like,
> * otherwise, it must be a safe source.
> */
> - if (safe_hardlink_source(inode) || inode_owner_or_capable(inode))
> + if (safe_hardlink_source(inode) || inode_owner_or_capable(&init_user_ns, inode))
> return 0;
>
> audit_log_path_denied(AUDIT_ANOM_LINK, "linkat");
> @@ -2897,7 +2897,7 @@ static int may_open(const struct path *path, int acc_mode, int flag)
> }
>
> /* O_NOATIME can only be set by the owner or superuser */
> - if (flag & O_NOATIME && !inode_owner_or_capable(inode))
> + if (flag & O_NOATIME && !inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> return 0;
> diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
> index b6517220cad5..d286c3bf7d43 100644
> --- a/fs/nilfs2/inode.c
> +++ b/fs/nilfs2/inode.c
> @@ -348,7 +348,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
> /* reference count of i_bh inherits from nilfs_mdt_read_block() */
>
> atomic64_inc(&root->inodes_count);
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_ino = ino;
> inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
>
> diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
> index 07d26f61f22a..b053b40315bf 100644
> --- a/fs/nilfs2/ioctl.c
> +++ b/fs/nilfs2/ioctl.c
> @@ -132,7 +132,7 @@ static int nilfs_ioctl_setflags(struct inode *inode, struct file *filp,
> unsigned int flags, oldflags;
> int ret;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (get_user(flags, (int __user *)argp))
> diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
> index 583820ec63e2..64491af88239 100644
> --- a/fs/ocfs2/dlmfs/dlmfs.c
> +++ b/fs/ocfs2/dlmfs/dlmfs.c
> @@ -329,7 +329,7 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
>
> if (inode) {
> inode->i_ino = get_next_ino();
> - inode_init_owner(inode, NULL, mode);
> + inode_init_owner(inode, &init_user_ns, NULL, mode);
> inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
> inc_nlink(inode);
>
> @@ -352,7 +352,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
> return NULL;
>
> inode->i_ino = get_next_ino();
> - inode_init_owner(inode, parent, mode);
> + inode_init_owner(inode, &init_user_ns, parent, mode);
> inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
>
> ip = DLMFS_I(inode);
> diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
> index 89984172fc4a..50c9b30ee9f6 100644
> --- a/fs/ocfs2/ioctl.c
> +++ b/fs/ocfs2/ioctl.c
> @@ -96,7 +96,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
> }
>
> status = -EACCES;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> goto bail_unlock;
>
> if (!S_ISDIR(inode->i_mode))
> diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
> index c46bf7f581a1..51a80acbb97e 100644
> --- a/fs/ocfs2/namei.c
> +++ b/fs/ocfs2/namei.c
> @@ -198,7 +198,7 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode)
> * callers. */
> if (S_ISDIR(mode))
> set_nlink(inode, 2);
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> status = dquot_initialize(inode);
> if (status)
> return ERR_PTR(status);
> diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c
> index ce93ccca8639..eed9e1273104 100644
> --- a/fs/omfs/inode.c
> +++ b/fs/omfs/inode.c
> @@ -48,7 +48,7 @@ struct inode *omfs_new_inode(struct inode *dir, umode_t mode)
> goto fail;
>
> inode->i_ino = new_block;
> - inode_init_owner(inode, NULL, mode);
> + inode_init_owner(inode, &init_user_ns, NULL, mode);
> inode->i_mapping->a_ops = &omfs_aops;
>
> inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index 28a075b5f5b2..80b2fab73df7 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -636,7 +636,7 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
> inode->i_state |= I_CREATING;
> spin_unlock(&inode->i_lock);
>
> - inode_init_owner(inode, dentry->d_parent->d_inode, mode);
> + inode_init_owner(inode, &init_user_ns, dentry->d_parent->d_inode, mode);
> attr.mode = inode->i_mode;
>
> err = ovl_create_or_link(dentry, inode, &attr, false);
> diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
> index f966b5108358..d58b49a1ea3b 100644
> --- a/fs/overlayfs/file.c
> +++ b/fs/overlayfs/file.c
> @@ -53,7 +53,7 @@ static struct file *ovl_open_realfile(const struct file *file,
> err = inode_permission(&init_user_ns, realinode, MAY_OPEN | acc_mode);
> if (err) {
> realfile = ERR_PTR(err);
> - } else if (!inode_owner_or_capable(realinode)) {
> + } else if (!inode_owner_or_capable(&init_user_ns, realinode)) {
> realfile = ERR_PTR(-EPERM);
> } else {
> realfile = open_with_fake_path(&file->f_path, flags, realinode,
> @@ -582,7 +582,7 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
> struct inode *inode = file_inode(file);
> unsigned int oldflags;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> ret = mnt_want_write_file(file);
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 196fe3e3f02b..82f2c35894e4 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -960,7 +960,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
> goto out_acl_release;
> }
> err = -EPERM;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> goto out_acl_release;
>
> posix_acl_release(acl);
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index ff67da201303..0a1f4bccb5da 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -481,7 +481,7 @@ struct file *ovl_path_open(struct path *path, int flags)
> return ERR_PTR(err);
>
> /* O_NOATIME is an optimization, don't fail if not permitted */
> - if (inode_owner_or_capable(inode))
> + if (inode_owner_or_capable(&init_user_ns, inode))
> flags |= O_NOATIME;
>
> return dentry_open(path, flags, current_cred());
> diff --git a/fs/posix_acl.c b/fs/posix_acl.c
> index 5b6296cc89c4..87b5ec67000b 100644
> --- a/fs/posix_acl.c
> +++ b/fs/posix_acl.c
> @@ -874,7 +874,7 @@ set_posix_acl(struct inode *inode, int type, struct posix_acl *acl)
>
> if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
> return acl ? -EACCES : 0;
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> if (acl) {
> diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
> index ee179a81b3da..83641b9614bd 100644
> --- a/fs/ramfs/inode.c
> +++ b/fs/ramfs/inode.c
> @@ -67,7 +67,7 @@ struct inode *ramfs_get_inode(struct super_block *sb,
>
> if (inode) {
> inode->i_ino = get_next_ino();
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_mapping->a_ops = &ramfs_aops;
> mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
> mapping_set_unevictable(inode->i_mapping);
> diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
> index adb21bea3d60..4f1cbd930179 100644
> --- a/fs/reiserfs/ioctl.c
> +++ b/fs/reiserfs/ioctl.c
> @@ -59,7 +59,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> if (err)
> break;
>
> - if (!inode_owner_or_capable(inode)) {
> + if (!inode_owner_or_capable(&init_user_ns, inode)) {
> err = -EPERM;
> goto setflags_out;
> }
> @@ -101,7 +101,7 @@ long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> err = put_user(inode->i_generation, (int __user *)arg);
> break;
> case REISERFS_IOC_SETVERSION:
> - if (!inode_owner_or_capable(inode)) {
> + if (!inode_owner_or_capable(&init_user_ns, inode)) {
> err = -EPERM;
> break;
> }
> diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
> index 1594687582f0..6e43aec49b43 100644
> --- a/fs/reiserfs/namei.c
> +++ b/fs/reiserfs/namei.c
> @@ -615,7 +615,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode)
> * the quota init calls have to know who to charge the quota to, so
> * we have to set uid and gid here
> */
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> return dquot_initialize(inode);
> }
>
> diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
> index 6c9801986af6..96288d35dcb9 100644
> --- a/fs/sysv/ialloc.c
> +++ b/fs/sysv/ialloc.c
> @@ -163,7 +163,7 @@ struct inode * sysv_new_inode(const struct inode * dir, umode_t mode)
> *sbi->s_sb_fic_count = cpu_to_fs16(sbi, count);
> fs16_add(sbi, sbi->s_sb_total_free_inodes, -1);
> dirty_sb(sb);
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_ino = fs16_to_cpu(sbi, ino);
> inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
> inode->i_blocks = 0;
> diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
> index 155521e51ac5..1639331f9543 100644
> --- a/fs/ubifs/dir.c
> +++ b/fs/ubifs/dir.c
> @@ -94,7 +94,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
> */
> inode->i_flags |= S_NOCMTIME;
>
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_mtime = inode->i_atime = inode->i_ctime =
> current_time(inode);
> inode->i_mapping->nrpages = 0;
> diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c
> index 4363d85a3fd4..2326d5122beb 100644
> --- a/fs/ubifs/ioctl.c
> +++ b/fs/ubifs/ioctl.c
> @@ -155,7 +155,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> if (IS_RDONLY(inode))
> return -EROFS;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EACCES;
>
> if (get_user(flags, (int __user *) arg))
> diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
> index 84ed23edebfd..e2d07cc1d3c3 100644
> --- a/fs/udf/ialloc.c
> +++ b/fs/udf/ialloc.c
> @@ -103,7 +103,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode)
> mutex_unlock(&sbi->s_alloc_mutex);
> }
>
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
> inode->i_uid = sbi->s_uid;
> if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET))
> diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
> index 969fd60436d3..a04c6ea490a0 100644
> --- a/fs/ufs/ialloc.c
> +++ b/fs/ufs/ialloc.c
> @@ -289,7 +289,7 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode)
> ufs_mark_sb_dirty(sb);
>
> inode->i_ino = cg * uspi->s_ipg + bit;
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_blocks = 0;
> inode->i_generation = 0;
> inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
> diff --git a/fs/xattr.c b/fs/xattr.c
> index 61a9947f62f4..fcc79c2a1ea1 100644
> --- a/fs/xattr.c
> +++ b/fs/xattr.c
> @@ -127,7 +127,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
> if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
> return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
> if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
> - (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
> + (mask & MAY_WRITE) && !inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
> }
>
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 97bd29fc8c43..218e80afc859 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -1300,7 +1300,7 @@ xfs_ioctl_setattr_get_trans(
> * The user ID of the calling process must be equal to the file owner
> * ID, except in cases where the CAP_FSETID capability is applicable.
> */
> - if (!inode_owner_or_capable(VFS_I(ip))) {
> + if (!inode_owner_or_capable(&init_user_ns, VFS_I(ip))) {
> error = -EPERM;
> goto out_cancel;
> }
> diff --git a/fs/zonefs/super.c b/fs/zonefs/super.c
> index ff5930be096c..5021a41e880c 100644
> --- a/fs/zonefs/super.c
> +++ b/fs/zonefs/super.c
> @@ -1221,7 +1221,7 @@ static void zonefs_init_dir_inode(struct inode *parent, struct inode *inode,
> struct super_block *sb = parent->i_sb;
>
> inode->i_ino = blkdev_nr_zones(sb->s_bdev->bd_disk) + type + 1;
> - inode_init_owner(inode, parent, S_IFDIR | 0555);
> + inode_init_owner(inode, &init_user_ns, parent, S_IFDIR | 0555);
> inode->i_op = &zonefs_dir_inode_operations;
> inode->i_fop = &simple_dir_operations;
> set_nlink(inode, 2);
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 8f6fb065450b..a5845a67a34b 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1744,7 +1744,7 @@ static inline int sb_start_intwrite_trylock(struct super_block *sb)
> }
>
>
> -extern bool inode_owner_or_capable(const struct inode *inode);
> +extern bool inode_owner_or_capable(struct user_namespace *user_ns, const struct inode *inode);
>
> /*
> * VFS helper functions..
> @@ -1786,8 +1786,9 @@ extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,
> /*
> * VFS file helper functions.
> */
> -extern void inode_init_owner(struct inode *inode, const struct inode *dir,
> - umode_t mode);
> +extern void inode_init_owner(struct inode *inode,
> + struct user_namespace *user_ns,
> + const struct inode *dir, umode_t mode);
> extern bool may_open_dev(const struct path *path);
>
> /*
> diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
> index f1c393e5d47d..cfd2e0868f2d 100644
> --- a/kernel/bpf/inode.c
> +++ b/kernel/bpf/inode.c
> @@ -122,7 +122,7 @@ static struct inode *bpf_get_inode(struct super_block *sb,
> inode->i_mtime = inode->i_atime;
> inode->i_ctime = inode->i_atime;
>
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
>
> return inode;
> }
> diff --git a/mm/madvise.c b/mm/madvise.c
> index 8afabc363b6b..a3ab05c08c28 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -539,7 +539,7 @@ static inline bool can_do_pageout(struct vm_area_struct *vma)
> * otherwise we'd be including shared non-exclusive mappings, which
> * opens a side channel.
> */
> - return inode_owner_or_capable(file_inode(vma->vm_file)) ||
> + return inode_owner_or_capable(&init_user_ns, file_inode(vma->vm_file)) ||
> inode_permission(&init_user_ns, file_inode(vma->vm_file), MAY_WRITE) == 0;
> }
>
> diff --git a/mm/mincore.c b/mm/mincore.c
> index d5a58e61eac6..ad2dfb7a4500 100644
> --- a/mm/mincore.c
> +++ b/mm/mincore.c
> @@ -166,7 +166,7 @@ static inline bool can_do_mincore(struct vm_area_struct *vma)
> * for writing; otherwise we'd be including shared non-exclusive
> * mappings, which opens a side channel.
> */
> - return inode_owner_or_capable(file_inode(vma->vm_file)) ||
> + return inode_owner_or_capable(&init_user_ns, file_inode(vma->vm_file)) ||
> inode_permission(&init_user_ns, file_inode(vma->vm_file), MAY_WRITE) == 0;
> }
>
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 537c137698f8..1bd6a9487222 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -2303,7 +2303,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
> inode = new_inode(sb);
> if (inode) {
> inode->i_ino = ino;
> - inode_init_owner(inode, dir, mode);
> + inode_init_owner(inode, &init_user_ns, dir, mode);
> inode->i_blocks = 0;
> inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
> inode->i_generation = prandom_u32();
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 6b1826fc3658..14a195fa55eb 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -3133,13 +3133,13 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
> }
>
> if (!selinux_initialized(&selinux_state))
> - return (inode_owner_or_capable(inode) ? 0 : -EPERM);
> + return (inode_owner_or_capable(&init_user_ns, inode) ? 0 : -EPERM);
>
> sbsec = inode->i_sb->s_security;
> if (!(sbsec->flags & SBLABEL_MNT))
> return -EOPNOTSUPP;
>
> - if (!inode_owner_or_capable(inode))
> + if (!inode_owner_or_capable(&init_user_ns, inode))
> return -EPERM;
>
> ad.type = LSM_AUDIT_DATA_DENTRY;
> --
> 2.29.2
Powered by blists - more mailing lists