Unverified Commit c7c7a1a1 authored by Tycho Andersen's avatar Tycho Andersen Committed by Christian Brauner
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJames Morris <jamorris@linux.microsoft.com>
Signed-off-by: default avatarTycho Andersen <tycho@tycho.pizza>
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
parent e65ce2a5
Loading
Loading
Loading
Loading
+14 −15
Original line number Diff line number Diff line
@@ -39,8 +39,8 @@ int cachefiles_check_object_type(struct cachefiles_object *object)
	_enter("%p{%s}", object, type);

	/* attempt to install a type label directly */
	ret = vfs_setxattr(dentry, cachefiles_xattr_cache, type, 2,
			   XATTR_CREATE);
	ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache, type,
			   2, XATTR_CREATE);
	if (ret == 0) {
		_debug("SET"); /* we succeeded */
		goto error;
@@ -54,7 +54,8 @@ int cachefiles_check_object_type(struct cachefiles_object *object)
	}

	/* read the current type label */
	ret = vfs_getxattr(dentry, cachefiles_xattr_cache, xtype, 3);
	ret = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, xtype,
			   3);
	if (ret < 0) {
		if (ret == -ERANGE)
			goto bad_type_length;
@@ -110,9 +111,8 @@ int cachefiles_set_object_xattr(struct cachefiles_object *object,
	_debug("SET #%u", auxdata->len);

	clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
			   &auxdata->type, auxdata->len,
			   XATTR_CREATE);
	ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
			   &auxdata->type, auxdata->len, XATTR_CREATE);
	if (ret < 0 && ret != -ENOMEM)
		cachefiles_io_error_obj(
			object,
@@ -140,9 +140,8 @@ int cachefiles_update_object_xattr(struct cachefiles_object *object,
	_debug("SET #%u", auxdata->len);

	clear_bit(FSCACHE_COOKIE_AUX_UPDATED, &object->fscache.cookie->flags);
	ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
			   &auxdata->type, auxdata->len,
			   XATTR_REPLACE);
	ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
			   &auxdata->type, auxdata->len, XATTR_REPLACE);
	if (ret < 0 && ret != -ENOMEM)
		cachefiles_io_error_obj(
			object,
@@ -171,7 +170,7 @@ int cachefiles_check_auxdata(struct cachefiles_object *object)
	if (!auxbuf)
		return -ENOMEM;

	xlen = vfs_getxattr(dentry, cachefiles_xattr_cache,
	xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
			    &auxbuf->type, 512 + 1);
	ret = -ESTALE;
	if (xlen < 1 ||
@@ -213,7 +212,7 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object,
	}

	/* read the current type label */
	ret = vfs_getxattr(dentry, cachefiles_xattr_cache,
	ret = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
			   &auxbuf->type, 512 + 1);
	if (ret < 0) {
		if (ret == -ENODATA)
@@ -270,9 +269,9 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object,
		}

		/* update the current label */
		ret = vfs_setxattr(dentry, cachefiles_xattr_cache,
				   &auxdata->type, auxdata->len,
				   XATTR_REPLACE);
		ret = vfs_setxattr(&init_user_ns, dentry,
				   cachefiles_xattr_cache, &auxdata->type,
				   auxdata->len, XATTR_REPLACE);
		if (ret < 0) {
			cachefiles_io_error_obj(object,
						"Can't update xattr on %lu"
@@ -309,7 +308,7 @@ int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
{
	int ret;

	ret = vfs_removexattr(dentry, cachefiles_xattr_cache);
	ret = vfs_removexattr(&init_user_ns, dentry, cachefiles_xattr_cache);
	if (ret < 0) {
		if (ret == -ENOENT || ret == -ENODATA)
			ret = 0;
+2 −2
Original line number Diff line number Diff line
@@ -1110,8 +1110,8 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,
	}

	inode_lock(lower_inode);
	rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
			    page_virt, size, 0);
	rc = __vfs_setxattr(&init_user_ns, lower_dentry, lower_inode,
			    ECRYPTFS_XATTR_NAME, page_virt, size, 0);
	if (!rc && ecryptfs_inode)
		fsstack_copy_attr_all(ecryptfs_inode, lower_inode);
	inode_unlock(lower_inode);
+3 −2
Original line number Diff line number Diff line
@@ -1024,7 +1024,8 @@ ecryptfs_setxattr(struct dentry *dentry, struct inode *inode,
		rc = -EOPNOTSUPP;
		goto out;
	}
	rc = vfs_setxattr(lower_dentry, name, value, size, flags);
	rc = vfs_setxattr(&init_user_ns, lower_dentry, name, value, size,
			  flags);
	if (!rc && inode)
		fsstack_copy_attr_all(inode, d_inode(lower_dentry));
out:
@@ -1089,7 +1090,7 @@ static int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode,
		goto out;
	}
	inode_lock(lower_inode);
	rc = __vfs_removexattr(lower_dentry, name);
	rc = __vfs_removexattr(&init_user_ns, lower_dentry, name);
	inode_unlock(lower_inode);
out:
	return rc;
+2 −2
Original line number Diff line number Diff line
@@ -426,8 +426,8 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
	if (size < 0)
		size = 8;
	put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);
	rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
			    xattr_virt, size, 0);
	rc = __vfs_setxattr(&init_user_ns, lower_dentry, lower_inode,
			    ECRYPTFS_XATTR_NAME, xattr_virt, size, 0);
	inode_unlock(lower_inode);
	if (rc)
		printk(KERN_ERR "Error whilst attempting to write inode size "
+8 −6
Original line number Diff line number Diff line
@@ -499,7 +499,8 @@ int nfsd4_is_junction(struct dentry *dentry)
		return 0;
	if (!(inode->i_mode & S_ISVTX))
		return 0;
	if (vfs_getxattr(dentry, NFSD_JUNCTION_XATTR_NAME, NULL, 0) <= 0)
	if (vfs_getxattr(&init_user_ns, dentry, NFSD_JUNCTION_XATTR_NAME,
			 NULL, 0) <= 0)
		return 0;
	return 1;
}
@@ -2149,7 +2150,7 @@ nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,

	inode_lock_shared(inode);

	len = vfs_getxattr(dentry, name, NULL, 0);
	len = vfs_getxattr(&init_user_ns, dentry, name, NULL, 0);

	/*
	 * Zero-length attribute, just return.
@@ -2176,7 +2177,7 @@ nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
		goto out;
	}

	len = vfs_getxattr(dentry, name, buf, len);
	len = vfs_getxattr(&init_user_ns, dentry, name, buf, len);
	if (len <= 0) {
		kvfree(buf);
		buf = NULL;
@@ -2283,7 +2284,8 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)

	fh_lock(fhp);

	ret = __vfs_removexattr_locked(fhp->fh_dentry, name, NULL);
	ret = __vfs_removexattr_locked(&init_user_ns, fhp->fh_dentry,
				       name, NULL);

	fh_unlock(fhp);
	fh_drop_write(fhp);
@@ -2307,8 +2309,8 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
		return nfserrno(ret);
	fh_lock(fhp);

	ret = __vfs_setxattr_locked(fhp->fh_dentry, name, buf, len, flags,
				    NULL);
	ret = __vfs_setxattr_locked(&init_user_ns, fhp->fh_dentry, name, buf,
				    len, flags, NULL);

	fh_unlock(fhp);
	fh_drop_write(fhp);
Loading