Skip to content

Commit

Permalink
acl: handle idmapped mounts
Browse files Browse the repository at this point in the history
The posix acl permission checking helpers determine whether a caller is
privileged over an inode according to the acls associated with the
inode. Add helpers that make it possible to handle acls on idmapped
mounts.

The vfs and the filesystems targeted by this first iteration make use of
posix_acl_fix_xattr_from_user() and posix_acl_fix_xattr_to_user() to
translate basic posix access and default permissions such as the
ACL_USER and ACL_GROUP type according to the initial user namespace (or
the superblock's user namespace) to and from the caller's current user
namespace. Adapt these two helpers to handle idmapped mounts whereby we
either map from or into the mount's user namespace depending on in which
direction we're translating.
Similarly, cap_convert_nscap() is used by the vfs to translate user
namespace and non-user namespace aware filesystem capabilities from the
superblock's user namespace to the caller's user namespace. Enable it to
handle idmapped mounts by accounting for the mount's user namespace.

In addition the fileystems targeted in the first iteration of this patch
series make use of the posix_acl_chmod() and, posix_acl_update_mode()
helpers. Both helpers perform permission checks on the target inode. Let
them handle idmapped mounts. These two helpers are called when posix
acls are set by the respective filesystems to handle this case we extend
the ->set() method to take an additional user namespace argument to pass
the mount's user namespace down.

Link: https://lore.kernel.org/r/20210121131959.646623-9-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>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
  • Loading branch information
Christian Brauner committed Jan 24, 2021
1 parent 2f221d6 commit e65ce2a
Show file tree
Hide file tree
Showing 72 changed files with 238 additions and 85 deletions.
7 changes: 4 additions & 3 deletions Documentation/filesystems/locking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,10 @@ prototypes::
int (*get)(const struct xattr_handler *handler, struct dentry *dentry,
struct inode *inode, const char *name, void *buffer,
size_t size);
int (*set)(const struct xattr_handler *handler, struct dentry *dentry,
struct inode *inode, const char *name, const void *buffer,
size_t size, int flags);
int (*set)(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode, const char *name,
const void *buffer, size_t size, int flags);

locking rules:
all may block
Expand Down
2 changes: 2 additions & 0 deletions Documentation/filesystems/porting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,8 @@ be removed. Switch while you still can; the old one won't stay.
**mandatory**

->setxattr() and xattr_handler.set() get dentry and inode passed separately.
The xattr_handler.set() gets passed the user namespace of the mount the inode
is seen from so filesystems can idmap the i_uid and i_gid accordingly.
dentry might be yet to be attached to inode, so do _not_ use its ->d_inode
in the instances. Rationale: !@#!@# security_d_instantiate() needs to be
called before we attach dentry to inode and !@#!@##!@$!$#!@#$!@$!@$ smack
Expand Down
4 changes: 3 additions & 1 deletion fs/9p/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
}

static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down Expand Up @@ -279,7 +280,8 @@ static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
struct iattr iattr = { 0 };
struct posix_acl *old_acl = acl;

retval = posix_acl_update_mode(inode, &iattr.ia_mode, &acl);
retval = posix_acl_update_mode(mnt_userns, inode,
&iattr.ia_mode, &acl);
if (retval)
goto err_out;
if (!acl) {
Expand Down
1 change: 1 addition & 0 deletions fs/9p/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
}

static int v9fs_xattr_handler_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
2 changes: 2 additions & 0 deletions fs/afs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ static const struct afs_operation_ops afs_store_acl_operation = {
* Set a file's AFS3 ACL.
*/
static int afs_xattr_set_acl(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry,
struct inode *inode, const char *name,
const void *buffer, size_t size, int flags)
Expand Down Expand Up @@ -248,6 +249,7 @@ static const struct afs_operation_ops yfs_store_opaque_acl2_operation = {
* Set a file's YFS ACL.
*/
static int afs_xattr_set_yfs(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry,
struct inode *inode, const char *name,
const void *buffer, size_t size, int flags)
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
umode_t old_mode = inode->i_mode;

if (type == ACL_TYPE_ACCESS && acl) {
ret = posix_acl_update_mode(inode, &inode->i_mode, &acl);
ret = posix_acl_update_mode(&init_user_ns, inode,
&inode->i_mode, &acl);
if (ret)
return ret;
}
Expand Down
3 changes: 2 additions & 1 deletion fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -5070,7 +5070,8 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
err = btrfs_dirty_inode(inode);

if (!err && attr->ia_valid & ATTR_MODE)
err = posix_acl_chmod(inode, inode->i_mode);
err = posix_acl_chmod(&init_user_ns, inode,
inode->i_mode);
}

return err;
Expand Down
2 changes: 2 additions & 0 deletions fs/btrfs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
}

static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *buffer,
size_t size, int flags)
Expand All @@ -371,6 +372,7 @@ static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
}

static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
3 changes: 2 additions & 1 deletion fs/ceph/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
case ACL_TYPE_ACCESS:
name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
ret = posix_acl_update_mode(inode, &new_mode, &acl);
ret = posix_acl_update_mode(&init_user_ns, inode,
&new_mode, &acl);
if (ret)
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 @@ -2262,7 +2262,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
err = __ceph_setattr(inode, attr);

if (err >= 0 && (attr->ia_valid & ATTR_MODE))
err = posix_acl_chmod(inode, attr->ia_mode);
err = posix_acl_chmod(&init_user_ns, inode, attr->ia_mode);

return err;
}
Expand Down
1 change: 1 addition & 0 deletions fs/ceph/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,7 @@ static int ceph_get_xattr_handler(const struct xattr_handler *handler,
}

static int ceph_set_xattr_handler(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/cifs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ static int cifs_creation_time_set(unsigned int xid, struct cifs_tcon *pTcon,
}

static int cifs_xattr_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/ecryptfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,7 @@ static int ecryptfs_xattr_get(const struct xattr_handler *handler,
}

static int ecryptfs_xattr_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value, size_t size,
int flags)
Expand Down
3 changes: 2 additions & 1 deletion fs/ext2/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,8 @@ ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
umode_t mode = inode->i_mode;

if (type == ACL_TYPE_ACCESS && acl) {
error = posix_acl_update_mode(inode, &mode, &acl);
error = posix_acl_update_mode(&init_user_ns, inode, &mode,
&acl);
if (error)
return error;
update_mode = 1;
Expand Down
2 changes: 1 addition & 1 deletion fs/ext2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
}
setattr_copy(&init_user_ns, inode, iattr);
if (iattr->ia_valid & ATTR_MODE)
error = posix_acl_chmod(inode, inode->i_mode);
error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
mark_inode_dirty(inode);

return error;
Expand Down
1 change: 1 addition & 0 deletions fs/ext2/xattr_security.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ext2_xattr_security_get(const struct xattr_handler *handler,

static int
ext2_xattr_security_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/ext2/xattr_trusted.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ ext2_xattr_trusted_get(const struct xattr_handler *handler,

static int
ext2_xattr_trusted_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/ext2/xattr_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ext2_xattr_user_get(const struct xattr_handler *handler,

static int
ext2_xattr_user_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
3 changes: 2 additions & 1 deletion fs/ext4/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
ext4_fc_start_update(inode);

if ((type == ACL_TYPE_ACCESS) && acl) {
error = posix_acl_update_mode(inode, &mode, &acl);
error = posix_acl_update_mode(&init_user_ns, inode, &mode,
&acl);
if (error)
goto out_stop;
if (mode != inode->i_mode)
Expand Down
2 changes: 1 addition & 1 deletion fs/ext4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -5524,7 +5524,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_orphan_del(NULL, inode);

if (!error && (ia_valid & ATTR_MODE))
rc = posix_acl_chmod(inode, inode->i_mode);
rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);

err_out:
if (error)
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/xattr_hurd.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ ext4_xattr_hurd_get(const struct xattr_handler *handler,

static int
ext4_xattr_hurd_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/xattr_security.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ ext4_xattr_security_get(const struct xattr_handler *handler,

static int
ext4_xattr_security_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/xattr_trusted.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ ext4_xattr_trusted_get(const struct xattr_handler *handler,

static int
ext4_xattr_trusted_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/xattr_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ext4_xattr_user_get(const struct xattr_handler *handler,

static int
ext4_xattr_user_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
3 changes: 2 additions & 1 deletion fs/f2fs/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ static int __f2fs_set_acl(struct inode *inode, int type,
case ACL_TYPE_ACCESS:
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
if (acl && !ipage) {
error = posix_acl_update_mode(inode, &mode, &acl);
error = posix_acl_update_mode(&init_user_ns, inode,
&mode, &acl);
if (error)
return error;
set_acl_inode(inode, mode);
Expand Down
7 changes: 4 additions & 3 deletions fs/f2fs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -831,8 +831,8 @@ int f2fs_getattr(const struct path *path, struct kstat *stat,
}

#ifdef CONFIG_F2FS_FS_POSIX_ACL
static void __setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
const struct iattr *attr)
static void __setattr_copy(struct user_namespace *mnt_userns,
struct inode *inode, const struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;

Expand Down Expand Up @@ -950,7 +950,8 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
__setattr_copy(&init_user_ns, inode, attr);

if (attr->ia_valid & ATTR_MODE) {
err = posix_acl_chmod(inode, f2fs_get_inode_mode(inode));
err = posix_acl_chmod(&init_user_ns, inode,
f2fs_get_inode_mode(inode));
if (err || is_inode_flag_set(inode, FI_ACL_MODE)) {
inode->i_mode = F2FS_I(inode)->i_acl_mode;
clear_inode_flag(inode, FI_ACL_MODE);
Expand Down
2 changes: 2 additions & 0 deletions fs/f2fs/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
}

static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down Expand Up @@ -107,6 +108,7 @@ static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
}

static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
2 changes: 2 additions & 0 deletions fs/fuse/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ static int fuse_xattr_get(const struct xattr_handler *handler,
}

static int fuse_xattr_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value, size_t size,
int flags)
Expand All @@ -214,6 +215,7 @@ static int no_xattr_get(const struct xattr_handler *handler,
}

static int no_xattr_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *dentry, struct inode *nodee,
const char *name, const void *value,
size_t size, int flags)
Expand Down
2 changes: 1 addition & 1 deletion fs/gfs2/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)

mode = inode->i_mode;
if (type == ACL_TYPE_ACCESS && acl) {
ret = posix_acl_update_mode(inode, &mode, &acl);
ret = posix_acl_update_mode(&init_user_ns, inode, &mode, &acl);
if (ret)
goto unlock;
}
Expand Down
3 changes: 2 additions & 1 deletion fs/gfs2/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1993,7 +1993,8 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
else {
error = gfs2_setattr_simple(inode, attr);
if (!error && attr->ia_valid & ATTR_MODE)
error = posix_acl_chmod(inode, inode->i_mode);
error = posix_acl_chmod(&init_user_ns, inode,
inode->i_mode);
}

error:
Expand Down
1 change: 1 addition & 0 deletions fs/gfs2/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,7 @@ int __gfs2_xattr_set(struct inode *inode, const char *name,
}

static int gfs2_xattr_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/hfs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ static int hfs_xattr_get(const struct xattr_handler *handler,
}

static int hfs_xattr_set(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *value, size_t size,
int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/hfsplus/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -858,6 +858,7 @@ static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
}

static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *buffer,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/hfsplus/xattr_security.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ static int hfsplus_security_getxattr(const struct xattr_handler *handler,
}

static int hfsplus_security_setxattr(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *buffer,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/hfsplus/xattr_trusted.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ static int hfsplus_trusted_getxattr(const struct xattr_handler *handler,
}

static int hfsplus_trusted_setxattr(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *buffer,
size_t size, int flags)
Expand Down
1 change: 1 addition & 0 deletions fs/hfsplus/xattr_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ static int hfsplus_user_getxattr(const struct xattr_handler *handler,
}

static int hfsplus_user_setxattr(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *buffer,
size_t size, int flags)
Expand Down
3 changes: 2 additions & 1 deletion fs/jffs2/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
if (acl) {
umode_t mode;

rc = posix_acl_update_mode(inode, &mode, &acl);
rc = posix_acl_update_mode(&init_user_ns, inode, &mode,
&acl);
if (rc)
return rc;
if (inode->i_mode != mode) {
Expand Down
2 changes: 1 addition & 1 deletion fs/jffs2/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)

rc = jffs2_do_setattr(inode, iattr);
if (!rc && (iattr->ia_valid & ATTR_MODE))
rc = posix_acl_chmod(inode, inode->i_mode);
rc = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);

return rc;
}
Expand Down
1 change: 1 addition & 0 deletions fs/jffs2/security.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ static int jffs2_security_getxattr(const struct xattr_handler *handler,
}

static int jffs2_security_setxattr(const struct xattr_handler *handler,
struct user_namespace *mnt_userns,
struct dentry *unused, struct inode *inode,
const char *name, const void *buffer,
size_t size, int flags)
Expand Down
Loading

0 comments on commit e65ce2a

Please sign in to comment.