Skip to content

Commit

Permalink
inode: make init and permission helpers idmapped mount aware
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christian Brauner committed Jan 24, 2021
1 parent 47291ba commit 21cb47b
Show file tree
Hide file tree
Showing 54 changed files with 112 additions and 91 deletions.
2 changes: 1 addition & 1 deletion fs/9p/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 3 additions & 3 deletions fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 :
Expand All @@ -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;
}

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fs/bfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/tests/btrfs-tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/crypto/policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion fs/efivarfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down
2 changes: 1 addition & 1 deletion fs/ext2/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(&init_user_ns, inode, dir, mode);

inode->i_ino = ino;
inode->i_blocks = 0;
Expand Down
6 changes: 3 additions & 3 deletions fs/ext2/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
15 changes: 8 additions & 7 deletions fs/ext4/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -1010,7 +1011,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);
Expand All @@ -1032,7 +1033,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);
Expand Down Expand Up @@ -1217,7 +1218,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;
Expand Down Expand Up @@ -1263,7 +1264,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)
Expand Down
14 changes: 7 additions & 7 deletions fs/f2fs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fs/f2fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/f2fs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/fcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion fs/hfsplus/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion fs/hfsplus/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/hugetlbfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 21cb47b

Please sign in to comment.