Skip to content

Commit

Permalink
namei: make permission helpers idmapped mount aware
Browse files Browse the repository at this point in the history
The two helpers inode_permission() and generic_permission() are used by
the vfs to perform basic permission checking by verifying that the
caller is privileged over an inode. In order to handle idmapped mounts
we extend the two helpers with an additional user namespace argument.
On idmapped mounts the two helpers will make sure to map the inode
according to the mount's user namespace and then peform identical
permission checks to inode_permission() and generic_permission(). 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/[email protected]
Cc: Christoph Hellwig <[email protected]>
Cc: David Howells <[email protected]>
Cc: Al Viro <[email protected]>
Cc: [email protected]
Reviewed-by: Christoph Hellwig <[email protected]>
Reviewed-by: James Morris <[email protected]>
Acked-by: Serge Hallyn <[email protected]>
Signed-off-by: Christian Brauner <[email protected]>
  • Loading branch information
Christian Brauner committed Jan 24, 2021
1 parent 0558c1b commit 47291ba
Show file tree
Hide file tree
Showing 36 changed files with 164 additions and 88 deletions.
3 changes: 2 additions & 1 deletion fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
return -EPERM;

if (!inode_owner_or_capable(inode)) {
error = inode_permission(inode, MAY_WRITE);
error = inode_permission(&init_user_ns, inode,
MAY_WRITE);
if (error)
return error;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -9889,7 +9889,7 @@ static int btrfs_permission(struct inode *inode, int mask)
if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
return -EACCES;
}
return generic_permission(inode, mask);
return generic_permission(&init_user_ns, inode, mask);
}

static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
Expand Down
12 changes: 7 additions & 5 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
BUG_ON(d_inode(victim->d_parent) != dir);
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);

error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
error = inode_permission(&init_user_ns, dir, MAY_WRITE | MAY_EXEC);
if (error)
return error;
if (IS_APPEND(dir))
Expand Down Expand Up @@ -951,7 +951,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
return -EEXIST;
if (IS_DEADDIR(dir))
return -ENOENT;
return inode_permission(dir, MAY_WRITE | MAY_EXEC);
return inode_permission(&init_user_ns, dir, MAY_WRITE | MAY_EXEC);
}

/*
Expand Down Expand Up @@ -2538,7 +2538,8 @@ static int btrfs_search_path_in_tree_user(struct inode *inode,
ret = PTR_ERR(temp_inode);
goto out_put;
}
ret = inode_permission(temp_inode, MAY_READ | MAY_EXEC);
ret = inode_permission(&init_user_ns, temp_inode,
MAY_READ | MAY_EXEC);
iput(temp_inode);
if (ret) {
ret = -EACCES;
Expand Down Expand Up @@ -3068,7 +3069,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
if (root == dest)
goto out_dput;

err = inode_permission(inode, MAY_WRITE | MAY_EXEC);
err = inode_permission(&init_user_ns, inode,
MAY_WRITE | MAY_EXEC);
if (err)
goto out_dput;
}
Expand Down Expand Up @@ -3139,7 +3141,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
* running and allows defrag on files open in read-only mode.
*/
if (!capable(CAP_SYS_ADMIN) &&
inode_permission(inode, MAY_WRITE)) {
inode_permission(&init_user_ns, inode, MAY_WRITE)) {
ret = -EPERM;
goto out;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/ceph/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2331,7 +2331,7 @@ int ceph_permission(struct inode *inode, int mask)
err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED, false);

if (!err)
err = generic_permission(inode, mask);
err = generic_permission(&init_user_ns, inode, mask);
return err;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static int cifs_permission(struct inode *inode, int mask)
on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits,
so allowing client to check permissions is useful */
return generic_permission(inode, mask);
return generic_permission(&init_user_ns, inode, mask);
}

static struct kmem_cache *cifs_inode_cachep;
Expand Down
3 changes: 2 additions & 1 deletion fs/configfs/symlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,8 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
if (dentry->d_inode || d_unhashed(dentry))
ret = -EEXIST;
else
ret = inode_permission(dir, MAY_WRITE | MAY_EXEC);
ret = inode_permission(&init_user_ns, dir,
MAY_WRITE | MAY_EXEC);
if (!ret)
ret = type->ct_item_ops->allow_link(parent_item, target_item);
if (!ret) {
Expand Down
3 changes: 2 additions & 1 deletion fs/ecryptfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,8 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
static int
ecryptfs_permission(struct inode *inode, int mask)
{
return inode_permission(ecryptfs_inode_to_lower(inode), mask);
return inode_permission(&init_user_ns,
ecryptfs_inode_to_lower(inode), mask);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -1404,7 +1404,7 @@ EXPORT_SYMBOL(begin_new_exec);
void would_dump(struct linux_binprm *bprm, struct file *file)
{
struct inode *inode = file_inode(file);
if (inode_permission(inode, MAY_READ) < 0) {
if (inode_permission(&init_user_ns, inode, MAY_READ) < 0) {
struct user_namespace *old, *user_ns;
bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;

Expand Down
5 changes: 3 additions & 2 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1280,15 +1280,16 @@ static int fuse_permission(struct inode *inode, int mask)
}

if (fc->default_permissions) {
err = generic_permission(inode, mask);
err = generic_permission(&init_user_ns, inode, mask);

/* If permission is denied, try to refresh file
attributes. This is also needed, because the root
node will at first have no permissions */
if (err == -EACCES && !refreshed) {
err = fuse_perm_getattr(inode, mask);
if (!err)
err = generic_permission(inode, mask);
err = generic_permission(&init_user_ns,
inode, mask);
}

/* Note: the opposite of the above test does not
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1852,7 +1852,7 @@ int gfs2_permission(struct inode *inode, int mask)
if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
error = -EPERM;
else
error = generic_permission(inode, mask);
error = generic_permission(&init_user_ns, inode, mask);
if (gfs2_holder_initialized(&i_gh))
gfs2_glock_dq_uninit(&i_gh);

Expand Down
2 changes: 1 addition & 1 deletion fs/hostfs/hostfs_kern.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,7 @@ static int hostfs_permission(struct inode *ino, int desired)
err = access_file(name, r, w, x);
__putname(name);
if (!err)
err = generic_permission(ino, desired);
err = generic_permission(&init_user_ns, ino, desired);
return err;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/kernfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ int kernfs_iop_permission(struct inode *inode, int mask)
kernfs_refresh_inode(kn, inode);
mutex_unlock(&kernfs_mutex);

return generic_permission(inode, mask);
return generic_permission(&init_user_ns, inode, mask);
}

int kernfs_xattr_get(struct kernfs_node *kn, const char *name,
Expand Down
7 changes: 6 additions & 1 deletion fs/libfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1318,9 +1318,14 @@ static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t siz
return -EOPNOTSUPP;
}

static int empty_dir_permission(struct inode *inode, int mask)
{
return generic_permission(&init_user_ns, inode, mask);
}

static const struct inode_operations empty_dir_inode_operations = {
.lookup = empty_dir_lookup,
.permission = generic_permission,
.permission = empty_dir_permission,
.setattr = empty_dir_setattr,
.getattr = empty_dir_getattr,
.listxattr = empty_dir_listxattr,
Expand Down
Loading

0 comments on commit 47291ba

Please sign in to comment.