Commit 07489bed authored by David Sterba's avatar David Sterba Committed by Ben Hutchings

btrfs: don't accept bare namespace as a valid xattr

commit 3c3b04d1 upstream.

Due to insufficient check in btrfs_is_valid_xattr, this unexpectedly
works:

 $ touch file
 $ setfattr -n user. -v 1 file
 $ getfattr -d file
user.="1"

ie. the missing attribute name after the namespace.

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=94291Reported-by: default avatarWilliam Douglas <william.douglas@intel.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.cz>
Signed-off-by: default avatarChris Mason <clm@fb.com>
[bwh: Backported to 3.2: XATTR_BTRFS_PREFIX is not supported]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
parent d7aac347
...@@ -310,21 +310,40 @@ const struct xattr_handler *btrfs_xattr_handlers[] = { ...@@ -310,21 +310,40 @@ const struct xattr_handler *btrfs_xattr_handlers[] = {
/* /*
* Check if the attribute is in a supported namespace. * Check if the attribute is in a supported namespace.
* *
* This applied after the check for the synthetic attributes in the system * This is applied after the check for the synthetic attributes in the system
* namespace. * namespace.
*/ */
static bool btrfs_is_valid_xattr(const char *name) static int btrfs_is_valid_xattr(const char *name)
{ {
return !strncmp(name, XATTR_SECURITY_PREFIX, int len = strlen(name);
XATTR_SECURITY_PREFIX_LEN) || int prefixlen = 0;
!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || if (!strncmp(name, XATTR_SECURITY_PREFIX,
!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); XATTR_SECURITY_PREFIX_LEN))
prefixlen = XATTR_SECURITY_PREFIX_LEN;
else if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
prefixlen = XATTR_SYSTEM_PREFIX_LEN;
else if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
prefixlen = XATTR_TRUSTED_PREFIX_LEN;
else if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
prefixlen = XATTR_USER_PREFIX_LEN;
else
return -EOPNOTSUPP;
/*
* The name cannot consist of just prefix
*/
if (len <= prefixlen)
return -EINVAL;
return 0;
} }
ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
void *buffer, size_t size) void *buffer, size_t size)
{ {
int ret;
/* /*
* If this is a request for a synthetic attribute in the system.* * If this is a request for a synthetic attribute in the system.*
* namespace use the generic infrastructure to resolve a handler * namespace use the generic infrastructure to resolve a handler
...@@ -333,8 +352,9 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name, ...@@ -333,8 +352,9 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
return generic_getxattr(dentry, name, buffer, size); return generic_getxattr(dentry, name, buffer, size);
if (!btrfs_is_valid_xattr(name)) ret = btrfs_is_valid_xattr(name);
return -EOPNOTSUPP; if (ret)
return ret;
return __btrfs_getxattr(dentry->d_inode, name, buffer, size); return __btrfs_getxattr(dentry->d_inode, name, buffer, size);
} }
...@@ -342,6 +362,7 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -342,6 +362,7 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags) size_t size, int flags)
{ {
struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
int ret;
/* /*
* The permission on security.* and system.* is not checked * The permission on security.* and system.* is not checked
...@@ -358,8 +379,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -358,8 +379,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
return generic_setxattr(dentry, name, value, size, flags); return generic_setxattr(dentry, name, value, size, flags);
if (!btrfs_is_valid_xattr(name)) ret = btrfs_is_valid_xattr(name);
return -EOPNOTSUPP; if (ret)
return ret;
if (size == 0) if (size == 0)
value = ""; /* empty EA, do not remove */ value = ""; /* empty EA, do not remove */
...@@ -371,6 +393,7 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -371,6 +393,7 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
int btrfs_removexattr(struct dentry *dentry, const char *name) int btrfs_removexattr(struct dentry *dentry, const char *name)
{ {
struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root; struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
int ret;
/* /*
* The permission on security.* and system.* is not checked * The permission on security.* and system.* is not checked
...@@ -387,8 +410,9 @@ int btrfs_removexattr(struct dentry *dentry, const char *name) ...@@ -387,8 +410,9 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
return generic_removexattr(dentry, name); return generic_removexattr(dentry, name);
if (!btrfs_is_valid_xattr(name)) ret = btrfs_is_valid_xattr(name);
return -EOPNOTSUPP; if (ret)
return ret;
return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0, return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
XATTR_REPLACE); XATTR_REPLACE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment