inode: make init and permission helpers idmapped mount aware
authorChristian Brauner <christian.brauner@ubuntu.com>
Thu, 21 Jan 2021 13:19:25 +0000 (14:19 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Sun, 24 Jan 2021 13:27:16 +0000 (14:27 +0100)
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 it according to the mount's user namespace. Afterwards the checks
are identical to non-idmapped mounts. If the initial user namespace is
passed nothing changes so non-idmapped mounts will see identical
behavior as before.

Similarly, 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 nothing changes so non-idmapped mounts
will see identical behavior as before.

Link: https://lore.kernel.org/r/20210121131959.646623-7-christian.brauner@ubuntu.com
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: James Morris <jamorris@linux.microsoft.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
54 files changed:
fs/9p/acl.c
fs/9p/vfs_inode.c
fs/attr.c
fs/bfs/dir.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/tests/btrfs-tests.c
fs/crypto/policy.c
fs/efivarfs/file.c
fs/ext2/ialloc.c
fs/ext2/ioctl.c
fs/ext4/ialloc.c
fs/ext4/ioctl.c
fs/f2fs/file.c
fs/f2fs/namei.c
fs/f2fs/xattr.c
fs/fcntl.c
fs/gfs2/file.c
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hugetlbfs/inode.c
fs/inode.c
fs/jfs/ioctl.c
fs/jfs/jfs_inode.c
fs/minix/bitmap.c
fs/namei.c
fs/nilfs2/inode.c
fs/nilfs2/ioctl.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/ioctl.c
fs/ocfs2/namei.c
fs/omfs/inode.c
fs/overlayfs/dir.c
fs/overlayfs/file.c
fs/overlayfs/super.c
fs/overlayfs/util.c
fs/posix_acl.c
fs/ramfs/inode.c
fs/reiserfs/ioctl.c
fs/reiserfs/namei.c
fs/sysv/ialloc.c
fs/ubifs/dir.c
fs/ubifs/ioctl.c
fs/udf/ialloc.c
fs/ufs/ialloc.c
fs/xattr.c
fs/xfs/xfs_ioctl.c
fs/zonefs/super.c
include/linux/fs.h
kernel/bpf/inode.c
mm/madvise.c
mm/mincore.c
mm/shmem.c
security/selinux/hooks.c

index 6261719f6f2a133c1f059cebaf470f3e28ef0b1c..d77b28e8d57aba6616b58adc00aa7a1d978708a6 100644 (file)
@@ -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 */
index 4a937fac1acb0f901c6456e426c03955355ddf50..f66eb3c12c8adeb6e982ba9431738ba742d46b33 100644 (file)
@@ -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(&init_user_ns,inode,  NULL, mode);
        inode->i_blocks = 0;
        inode->i_rdev = rdev;
        inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
index c9e29e589cecca6dff302723f51a815e964394be..00ae0b000146f3b717dbfab56160b18129e91395 100644 (file)
--- 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)
index d8dfe3a0cb390db6639ad59836af75f1548aafbe..be1335a8d25ba29c302ce7cc403fadef3978a754 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
        inode->i_blocks = 0;
        inode->i_op = &bfs_file_inops;
index 512ee2650bbba15f97c37ca531a7bf0a3177f426..07fe8b2f3babd68a6cdf324f5dfaf31da04b9339 100644 (file)
@@ -6190,7 +6190,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(&init_user_ns, inode, dir, mode);
        inode_set_bytes(inode, 0);
 
        inode->i_mtime = current_time(inode);
index 8ced6dfefee4b138c716b5f2dcdad96f6ec5eb08..1f763c60415b3742053645e78aa6fb57d40c26a1 100644 (file)
@@ -213,7 +213,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))
@@ -429,7 +429,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))
@@ -1862,7 +1862,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
@@ -1982,7 +1982,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);
@@ -4453,7 +4453,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);
index 6bd97bd4cb37114720393f252202844dd9653593..3a4099a2bf051d5bc288fed5057a9e1dbd23de13 100644 (file)
@@ -62,7 +62,7 @@ struct inode *btrfs_new_test_inode(void)
        BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
        BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
        BTRFS_I(inode)->location.offset = 0;
-       inode_init_owner(inode, NULL, S_IFREG);
+       inode_init_owner(&init_user_ns, inode, NULL, S_IFREG);
 
        return inode;
 }
index a51cef6bd27ff48a3073ca3ced74696a40b2ba53..ed3d623724cddbc0cef5b06948db83726f87b574 100644 (file)
@@ -465,7 +465,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);
index feaa5e182b7b4c71c33aa712646dc87e9a67c49f..e6bc0302643bb8c6dac0c5975a1e6f99ccf97033 100644 (file)
@@ -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)))
index 432c3febea6df969c53ac7ec5b1b76578b93baa0..df14e750e9fe3c17dfa21e3fbcfa71f9e79471e4 100644 (file)
@@ -551,7 +551,7 @@ got:
                inode->i_uid = current_fsuid();
                inode->i_gid = dir->i_gid;
        } else
-               inode_init_owner(inode, dir, mode);
+               inode_init_owner(&init_user_ns, inode, dir, mode);
 
        inode->i_ino = ino;
        inode->i_blocks = 0;
index 32a8d10b579df71a75ee13b645ece202e167d908..b399cbb7022df5075717109cc5c425b4d9a44eba 100644 (file)
@@ -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 @@ setflags_out:
        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 @@ setversion_out:
                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))
index b215c564bc318a5aaf883f8f6e5a1ba6013a201f..00c1ec6eee16a87b79c5814cb833461a3d606001 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
 
        if (ext4_has_feature_project(sb) &&
            ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT))
index d9665d2f82db845175e290b70d1ea7cb26f9b938..ab80e2493fdca1fec58272ebf3f2f94701cbcd30 100644 (file)
@@ -139,7 +139,8 @@ 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 +830,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 +872,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 +1011,7 @@ mext_out:
        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 +1033,7 @@ mext_out:
        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);
@@ -1217,7 +1218,7 @@ resizefs_out:
 
        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;
@@ -1263,7 +1264,7 @@ resizefs_out:
                        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)
index f585545277d775b36824bba05c7de46ea694e07f..5fc0ff28b5ddb560873545ab221547baa6626e5e 100644 (file)
@@ -1961,7 +1961,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))
@@ -2008,7 +2008,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))
@@ -2075,7 +2075,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);
@@ -2117,7 +2117,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))
@@ -2152,7 +2152,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);
@@ -2181,7 +2181,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);
@@ -3158,7 +3158,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)
index 6edb1ab579a18b2e3d270aadaced354b63d6648d..ad98926bacacca26694fe84ff2bd7af070c847c1 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
 
        inode->i_ino = ino;
        inode->i_blocks = 0;
index 65afcc3cc68a0e225912da649bfc90847fec0bf8..d772bf13a8145f339c5d92001b6e15987d00044b 100644 (file)
@@ -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;
index 05b36b28f2e87fbf303b6329e4a16ec23c7c9269..74d99731fd434aaf3d934a023179b8c68c8f49d4 100644 (file)
@@ -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 */
index b39b339feddc934c39f58c1374695e98aeac32de..1d994bdfffaa83c55c6f3e28d04d95436e023338 100644 (file)
@@ -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;
index e3da9e96b83578d7f8989dab58a9a69a84ac6f92..21357046b0396d949aee02db5aa57b3c0fdcd844 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        set_nlink(inode, 1);
        inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
 
index ce15b9496b77e058e331afa0a4a1ea83c9c3011a..3edb1926d1272335584707963e7780a6b27ea2e9 100644 (file)
@@ -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;
        }
index b5c109703daaf9ff2f4384c1f53e15ee1c5f3e55..6737929e443ca4bacdd45b7b504e02c313adb364 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
                lockdep_set_class(&inode->i_mapping->i_mmap_rwsem,
                                &hugetlbfs_i_mmap_rwsem_key);
                inode->i_mapping->a_ops = &hugetlbfs_aops;
index cd40cbf87ce4acab1f74210dcc3773374b2e779b..a9ac97a2778487b872fe9c9560094857ff496b3e 100644 (file)
@@ -2130,14 +2130,21 @@ EXPORT_SYMBOL(init_special_inode);
 
 /**
  * inode_init_owner - Init uid,gid,mode for new inode according to posix standards
+ * @mnt_userns:        User namespace of the mount the inode was created from
  * @inode: New inode
  * @dir: Directory inode
  * @mode: mode of the new inode
+ *
+ * If the inode has been created through an idmapped mount the user namespace of
+ * the vfsmount must be passed through @mnt_userns. This function will then take
+ * care to map the inode according to @mnt_userns before checking permissions
+ * and initializing i_uid and i_gid. On non-idmapped mounts or if permission
+ * checking is to be performed on the raw inode simply passs init_user_ns.
  */
-void inode_init_owner(struct inode *inode, const struct inode *dir,
-                       umode_t mode)
+void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
+                     const struct inode *dir, umode_t mode)
 {
-       inode->i_uid = current_fsuid();
+       inode->i_uid = fsuid_into_mnt(mnt_userns);
        if (dir && dir->i_mode & S_ISGID) {
                inode->i_gid = dir->i_gid;
 
@@ -2145,32 +2152,41 @@ 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(mnt_userns, dir)) &&
+                        !capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
                        mode &= ~S_ISGID;
        } else
-               inode->i_gid = current_fsgid();
+               inode->i_gid = fsgid_into_mnt(mnt_userns);
        inode->i_mode = mode;
 }
 EXPORT_SYMBOL(inode_init_owner);
 
 /**
  * inode_owner_or_capable - check current task permissions to inode
+ * @mnt_userns:        user namespace of the mount the inode was found 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.
+ *
+ * If the inode has been found through an idmapped mount the user namespace of
+ * the vfsmount must be passed through @mnt_userns. This function will then take
+ * care to map the inode according to @mnt_userns before checking permissions.
+ * On non-idmapped mounts or if permission checking is to be performed on the
+ * raw inode simply passs init_user_ns.
  */
-bool inode_owner_or_capable(const struct inode *inode)
+bool inode_owner_or_capable(struct user_namespace *mnt_userns,
+                           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(mnt_userns, inode);
+       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;
 }
index 10ee0ecca1a82ff8c1a80e8c48cc60f7d63202d1..2581d4db58fff2b258377c3a8ec18de15072cf4f 100644 (file)
@@ -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;
                }
index 4cef170630db4c77af8a345b4fba0cc2807cd334..59379089e939efd5ceaa38ac1b08a99abe2bf036 100644 (file)
@@ -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(&init_user_ns, inode, parent, mode);
        /*
         * New inodes need to save sane values on disk when
         * uid & gid mount options are used
index f4e5e5181a144b5d78d65c14a89258014f2fff1e..9115948c624ee43fff95c56f9f3da71ff7ef8bcf 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        inode->i_ino = j;
        inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
        inode->i_blocks = 0;
index d78d74f5f5af9eced94db488d063c56f8e369b98..04b001ddade31a7c584a43f3a51a1a27d4e30226 100644 (file)
@@ -1088,7 +1088,8 @@ 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");
@@ -2940,7 +2941,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;
index b6517220cad54d7a41abedbaeb46b3685e697d5c..11225a65973697402f08dfc68115cef1ea90cc13 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        inode->i_ino = ino;
        inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
 
index 07d26f61f22aa5b92d28adba4bed97791b735f92..b053b40315bf2b2264ab7a08e5166af517869aa9 100644 (file)
@@ -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))
index 583820ec63e2d80173bbd3cc332d311a03456102..37c7d03a6284a36a1633ebfec3b02bdfffb6cd28 100644 (file)
@@ -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(&init_user_ns, inode, 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(&init_user_ns, inode, parent, mode);
        inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
 
        ip = DLMFS_I(inode);
index 89984172fc4aef0a88f92151d8bb982cb4779b6d..50c9b30ee9f6f02466f1ec28c5cb3011e3a92287 100644 (file)
@@ -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))
index 2a237ab00453c4648f467048ee133d97ebb68f62..908b79e1082bc4f5fac3ec2a359a6e29306e0b05 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        status = dquot_initialize(inode);
        if (status)
                return ERR_PTR(status);
index ce93ccca86392badb8e7ecb490f0252e5342484d..2a0e83236c0115f938dc209c059533dbeb0f0246 100644 (file)
@@ -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(&init_user_ns, inode, NULL, mode);
        inode->i_mapping->a_ops = &omfs_aops;
 
        inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
index 28a075b5f5b2eb2e2391d8b341d3844723ed48b9..98a23353b19adf0f33ac1ebd0b169f170fa5395c 100644 (file)
@@ -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(&init_user_ns, inode, dentry->d_parent->d_inode, mode);
        attr.mode = inode->i_mode;
 
        err = ovl_create_or_link(dentry, inode, &attr, false);
index b2948e7b3210e323aa7dca5738df7e657182b8a7..7d8b84c715b3e4c24523d1939560b96ea6d7632b 100644 (file)
@@ -54,7 +54,7 @@ static struct file *ovl_open_realfile(const struct file *file,
        if (err) {
                realfile = ERR_PTR(err);
        } else {
-               if (!inode_owner_or_capable(realinode))
+               if (!inode_owner_or_capable(&init_user_ns, realinode))
                        flags &= ~O_NOATIME;
 
                realfile = open_with_fake_path(&file->f_path, flags, realinode,
@@ -520,7 +520,7 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
        long ret;
        struct inode *inode = file_inode(file);
 
-       if (!inode_owner_or_capable(inode))
+       if (!inode_owner_or_capable(&init_user_ns, inode))
                return -EACCES;
 
        ret = mnt_want_write_file(file);
index 88d8777877700a60008d3200578f281547bcf30b..3e925deaa19a78058e97becd0f198fd33a692556 100644 (file)
@@ -1005,7 +1005,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);
index de5c2047a0e9756f25bf932a074121bb43d04e07..06013b7b1e87a5c63a9627680f0fc89f04e969f7 100644 (file)
@@ -484,7 +484,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());
index 5d9fe2fb295314078d740373de31863675408c85..9ce8214bfdacdbff085c7f9f20080d6df8f36156 100644 (file)
@@ -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) {
index ee179a81b3da8f2a987716944b842073f81e0780..3fd4326f36b519e5b36478089cfc5605ac040dc8 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
                inode->i_mapping->a_ops = &ramfs_aops;
                mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
                mapping_set_unevictable(inode->i_mapping);
index adb21bea3d600e7f079d4868d44279c39904c99f..4f1cbd9301792fb1ecb4884e925bc7854da5bbde 100644 (file)
@@ -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 @@ setflags_out:
                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;
                }
index 1594687582f0cd47ad52c16a6bbd729af89a46bf..a67a7d371725d358e42947220cf6a52c880ba5bb 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        return dquot_initialize(inode);
 }
 
index 6c9801986af6d5de4c3c833966608afb514ba7d5..50df794a3c1f70d0fa1964a7a48c9cf475197635 100644 (file)
@@ -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(&init_user_ns, inode, 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;
index 9a6b8660425a4305f3f48f2acb185c6bc2934b53..694e7714545bc7c35417bc06221248b0b26ab658 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
        inode->i_mtime = inode->i_atime = inode->i_ctime =
                         current_time(inode);
        inode->i_mapping->nrpages = 0;
index 4363d85a3fd4010f7b189ce419edecc3a76e0cba..2326d5122beb7e498922bd04ad75c45bef44267a 100644 (file)
@@ -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))
index 84ed23edebfd379fa5906860758e3fe44a09da18..2ecf0e87660e3226018e5bfaf9580d84877a5251 100644 (file)
@@ -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(&init_user_ns, inode, 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))
index 969fd60436d395ec6fbf8606aa1308e05748c25a..7e3e08c0166f779f96d8524a97bb3b48def6c90d 100644 (file)
@@ -289,7 +289,7 @@ cg_found:
        ufs_mark_sb_dirty(sb);
 
        inode->i_ino = cg * uspi->s_ipg + bit;
-       inode_init_owner(inode, dir, mode);
+       inode_init_owner(&init_user_ns, inode, dir, mode);
        inode->i_blocks = 0;
        inode->i_generation = 0;
        inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
index 56151bd9e642b7f16513ddc2a55c508dd6670fc7..c669922e1bdead57ae52e33f95d1f2e2ff0c9ea7 100644 (file)
@@ -127,7 +127,8 @@ 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;
        }
 
index 97bd29fc8c43fbc2189ec2dc5ae8cf8d75cad2ba..218e80afc859bb0ee1bc31c938b6f6f520940904 100644 (file)
@@ -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;
        }
index bec47f2d074beb1e00379cfef9940ebac238c203..569525ee8f69725f25aac3dc009aaca49e6aa073 100644 (file)
@@ -1223,7 +1223,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(&init_user_ns, inode, parent, S_IFDIR | 0555);
        inode->i_op = &zonefs_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
        set_nlink(inode, 2);
index a85dfe6962dfd1982c406733f8d102216dc77ee0..2a9d4af6a64d70b568b057fec7cce3c99bce27c8 100644 (file)
@@ -1762,8 +1762,8 @@ static inline bool sb_start_intwrite_trylock(struct super_block *sb)
        return __sb_start_write_trylock(sb, SB_FREEZE_FS);
 }
 
-
-extern bool inode_owner_or_capable(const struct inode *inode);
+bool inode_owner_or_capable(struct user_namespace *mnt_userns,
+                           const struct inode *inode);
 
 /*
  * VFS helper functions..
@@ -1805,8 +1805,8 @@ 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);
+void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
+                     const struct inode *dir, umode_t mode);
 extern bool may_open_dev(const struct path *path);
 
 /*
index e3226b65f5dc8faff9652dff8f191f61ed9c080b..05b1f51d15e0ac7bbe967aca90a66f5e2fa7f23a 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
 
        return inode;
 }
index 175c5582d8a93585dd83bbc4e30fad8eccd28c3f..d4f5eece9d56b5a6870ea106d74acaac5bf31596 100644 (file)
@@ -539,7 +539,8 @@ 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)) ||
               file_permission(vma->vm_file, MAY_WRITE) == 0;
 }
 
index 7bdb4673f776ab8e9a6ea34af7727d0fbb7326d2..9122676b54d67c4914543146a07f2491c3262f12 100644 (file)
@@ -166,7 +166,8 @@ 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)) ||
               file_permission(vma->vm_file, MAY_WRITE) == 0;
 }
 
index 7c6b6d8f6c396d5c9f608a17983fbe7691c6b9cf..1c68c9edba5e933ed5831d68d2b3077d2b6f4151 100644 (file)
@@ -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(&init_user_ns, inode, dir, mode);
                inode->i_blocks = 0;
                inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
                inode->i_generation = prandom_u32();
index 644b17ec9e63abca1715e04de51343fdfbe1be29..9d6d3da2caf21d5ea09c07a6dda7f6f74c53fac1 100644 (file)
@@ -3140,13 +3140,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;