xattr: handle idmapped mounts

When interacting with extended attributes the vfs verifies that the
caller is privileged over the inode with which the extended attribute is
associated. For posix access and posix default extended attributes a uid
or gid can be stored on-disk. Let the functions handle posix extended
attributes on idmapped mounts. If the inode is accessed through an
idmapped mount we need to map it according to the mount's user
namespace. Afterwards the checks are identical to non-idmapped mounts.
This has no effect for e.g. security xattrs since they don't store uids
or gids and don't perform permission checks on them like posix acls do.

Link: https://lore.kernel.org/r/20210121131959.646623-10-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: Tycho Andersen <tycho@tycho.pizza>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
Tycho Andersen
2021-01-21 14:19:28 +01:00
committed by Christian Brauner
parent e65ce2a50c
commit c7c7a1a18a
19 changed files with 160 additions and 124 deletions

View File

@@ -324,8 +324,8 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
d = bprm->file->f_path.dentry;
for (i = 0; i < profile->xattr_count; i++) {
size = vfs_getxattr_alloc(d, profile->xattrs[i], &value,
value_size, GFP_KERNEL);
size = vfs_getxattr_alloc(&init_user_ns, d, profile->xattrs[i],
&value, value_size, GFP_KERNEL);
if (size >= 0) {
u32 perm;

View File

@@ -313,7 +313,7 @@ int cap_inode_killpriv(struct dentry *dentry)
{
int error;
error = __vfs_removexattr(dentry, XATTR_NAME_CAPS);
error = __vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_CAPS);
if (error == -EOPNOTSUPP)
error = 0;
return error;
@@ -386,8 +386,8 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
return -EINVAL;
size = sizeof(struct vfs_ns_cap_data);
ret = (int) vfs_getxattr_alloc(dentry, XATTR_NAME_CAPS,
&tmpbuf, size, GFP_NOFS);
ret = (int)vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_CAPS,
&tmpbuf, size, GFP_NOFS);
dput(dentry);
if (ret < 0)

View File

@@ -222,7 +222,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
ima_present = true;
continue;
}
size = vfs_getxattr_alloc(dentry, xattr->name,
size = vfs_getxattr_alloc(&init_user_ns, dentry, xattr->name,
&xattr_value, xattr_size, GFP_NOFS);
if (size == -ENOMEM) {
error = -ENOMEM;
@@ -275,8 +275,8 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
return 1;
/* Do this the hard way */
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
rc = vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_EVM,
(char **)&xattr_data, 0, GFP_NOFS);
if (rc <= 0) {
if (rc == -ENODATA)
return 0;
@@ -319,11 +319,12 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
xattr_value_len, &data);
if (rc == 0) {
data.hdr.xattr.sha1.type = EVM_XATTR_HMAC;
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
rc = __vfs_setxattr_noperm(&init_user_ns, dentry,
XATTR_NAME_EVM,
&data.hdr.xattr.data[1],
SHA1_DIGEST_SIZE + 1, 0);
} else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
rc = __vfs_removexattr(dentry, XATTR_NAME_EVM);
rc = __vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_EVM);
}
return rc;
}

View File

@@ -146,8 +146,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
/* if status is not PASS, try to check again - against -ENOMEM */
/* first need to know the sig type */
rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
GFP_NOFS);
rc = vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_EVM,
(char **)&xattr_data, 0, GFP_NOFS);
if (rc <= 0) {
evm_status = INTEGRITY_FAIL;
if (rc == -ENODATA) {

View File

@@ -94,7 +94,7 @@ static int ima_fix_xattr(struct dentry *dentry,
iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG;
iint->ima_hash->xattr.ng.algo = algo;
}
rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA,
rc = __vfs_setxattr_noperm(&init_user_ns, dentry, XATTR_NAME_IMA,
&iint->ima_hash->xattr.data[offset],
(sizeof(iint->ima_hash->xattr) - offset) +
iint->ima_hash->length, 0);
@@ -215,8 +215,8 @@ int ima_read_xattr(struct dentry *dentry,
{
ssize_t ret;
ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
0, GFP_NOFS);
ret = vfs_getxattr_alloc(&init_user_ns, dentry, XATTR_NAME_IMA,
(char **)xattr_value, 0, GFP_NOFS);
if (ret == -EOPNOTSUPP)
ret = 0;
return ret;
@@ -520,7 +520,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
if (!action)
__vfs_removexattr(dentry, XATTR_NAME_IMA);
__vfs_removexattr(&init_user_ns, dentry, XATTR_NAME_IMA);
iint = integrity_iint_find(inode);
if (iint) {
set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags);

View File

@@ -6526,7 +6526,8 @@ static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen
*/
static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
{
return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
return __vfs_setxattr_noperm(&init_user_ns, dentry, XATTR_NAME_SELINUX,
ctx, ctxlen, 0);
}
static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)

View File

@@ -3425,7 +3425,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
if (isp->smk_flags & SMK_INODE_CHANGED) {
isp->smk_flags &= ~SMK_INODE_CHANGED;
rc = __vfs_setxattr(dp, inode,
rc = __vfs_setxattr(&init_user_ns, dp, inode,
XATTR_NAME_SMACKTRANSMUTE,
TRANS_TRUE, TRANS_TRUE_SIZE,
0);
@@ -4597,12 +4597,14 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0);
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx,
ctxlen, 0);
}
static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
{
return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0);
return __vfs_setxattr_noperm(&init_user_ns, dentry, XATTR_NAME_SMACK,
ctx, ctxlen, 0);
}
static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)