Commit f6fbd8cb authored by Paul Moore's avatar Paul Moore
Browse files

lsm,fs: fix vfs_getxattr_alloc() return type and caller error paths



The vfs_getxattr_alloc() function currently returns a ssize_t value
despite the fact that it only uses int values internally for return
values.  Fix this by converting vfs_getxattr_alloc() to return an
int type and adjust the callers as necessary.  As part of these
caller modifications, some of the callers are fixed to properly free
the xattr value buffer on both success and failure to ensure that
memory is not leaked in the failure case.

Reviewed-by: default avatarSerge Hallyn <serge@hallyn.com>
Reviewed-by: default avatarMimi Zohar <zohar@linux.ibm.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent e68bfbd3
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -354,11 +354,12 @@ xattr_getsecurity(struct user_namespace *mnt_userns, struct inode *inode,
 * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
 *
 * Allocate memory, if not already allocated, or re-allocate correct size,
 * before retrieving the extended attribute.
 * before retrieving the extended attribute.  The xattr value buffer should
 * always be freed by the caller, even on error.
 *
 * Returns the result of alloc, if failed, or the getxattr operation.
 */
ssize_t
int
vfs_getxattr_alloc(struct user_namespace *mnt_userns, struct dentry *dentry,
		   const char *name, char **xattr_value, size_t xattr_size,
		   gfp_t flags)
+3 −3
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ int __vfs_removexattr_locked(struct user_namespace *, struct dentry *,
int vfs_removexattr(struct user_namespace *, struct dentry *, const char *);

ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
ssize_t vfs_getxattr_alloc(struct user_namespace *mnt_userns,
int vfs_getxattr_alloc(struct user_namespace *mnt_userns,
		       struct dentry *dentry, const char *name,
		       char **xattr_value, size_t size, gfp_t flags);

+1 −2
Original line number Diff line number Diff line
@@ -311,10 +311,9 @@ static int aa_xattrs_match(const struct linux_binprm *bprm,
			   struct aa_profile *profile, unsigned int state)
{
	int i;
	ssize_t size;
	struct dentry *d;
	char *value = NULL;
	int value_size = 0, ret = profile->xattr_count;
	int size, value_size = 0, ret = profile->xattr_count;

	if (!bprm || !profile->xattr_count)
		return 0;
+10 −12
Original line number Diff line number Diff line
@@ -350,14 +350,14 @@ static __u32 sansflags(__u32 m)
	return m & ~VFS_CAP_FLAGS_EFFECTIVE;
}

static bool is_v2header(size_t size, const struct vfs_cap_data *cap)
static bool is_v2header(int size, const struct vfs_cap_data *cap)
{
	if (size != XATTR_CAPS_SZ_2)
		return false;
	return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2;
}

static bool is_v3header(size_t size, const struct vfs_cap_data *cap)
static bool is_v3header(int size, const struct vfs_cap_data *cap)
{
	if (size != XATTR_CAPS_SZ_3)
		return false;
@@ -379,7 +379,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
			  struct inode *inode, const char *name, void **buffer,
			  bool alloc)
{
	int size, ret;
	int size;
	kuid_t kroot;
	u32 nsmagic, magic;
	uid_t root, mappedroot;
@@ -395,20 +395,18 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
	dentry = d_find_any_alias(inode);
	if (!dentry)
		return -EINVAL;

	size = sizeof(struct vfs_ns_cap_data);
	ret = (int)vfs_getxattr_alloc(mnt_userns, dentry, XATTR_NAME_CAPS,
				      &tmpbuf, size, GFP_NOFS);
	size = vfs_getxattr_alloc(mnt_userns, dentry, XATTR_NAME_CAPS, &tmpbuf,
				  sizeof(struct vfs_ns_cap_data), GFP_NOFS);
	dput(dentry);

	if (ret < 0 || !tmpbuf)
		return ret;
	/* gcc11 complains if we don't check for !tmpbuf */
	if (size < 0 || !tmpbuf)
		goto out_free;

	fs_ns = inode->i_sb->s_user_ns;
	cap = (struct vfs_cap_data *) tmpbuf;
	if (is_v2header((size_t) ret, cap)) {
	if (is_v2header(size, cap)) {
		root = 0;
	} else if (is_v3header((size_t) ret, cap)) {
	} else if (is_v3header(size, cap)) {
		nscap = (struct vfs_ns_cap_data *) tmpbuf;
		root = le32_to_cpu(nscap->rootid);
	} else {
+3 −2
Original line number Diff line number Diff line
@@ -335,14 +335,15 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode)
				(char **)&xattr_data, 0, GFP_NOFS);
	if (rc <= 0) {
		if (rc == -ENODATA)
			return 0;
		return rc;
			rc = 0;
		goto out;
	}
	if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG)
		rc = 1;
	else
		rc = 0;

out:
	kfree(xattr_data);
	return rc;
}
Loading