mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
btrfs: don't accept bare namespace as a valid xattr
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=94291 Reported-by: William Douglas <william.douglas@intel.com> CC: <stable@vger.kernel.org> # 2.6.29+ Signed-off-by: David Sterba <dsterba@suse.cz> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
dcc82f4783
commit
3c3b04d10f
1 changed files with 39 additions and 14 deletions
|
@ -364,22 +364,42 @@ const struct xattr_handler *btrfs_xattr_handlers[] = {
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
static bool btrfs_is_valid_xattr(const char *name)
|
||||
static int btrfs_is_valid_xattr(const char *name)
|
||||
{
|
||||
return !strncmp(name, XATTR_SECURITY_PREFIX,
|
||||
XATTR_SECURITY_PREFIX_LEN) ||
|
||||
!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
|
||||
!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
|
||||
!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) ||
|
||||
!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN);
|
||||
int len = strlen(name);
|
||||
int prefixlen = 0;
|
||||
|
||||
if (!strncmp(name, XATTR_SECURITY_PREFIX,
|
||||
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 if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
|
||||
prefixlen = XATTR_BTRFS_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,
|
||||
void *buffer, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If this is a request for a synthetic attribute in the system.*
|
||||
* namespace use the generic infrastructure to resolve a handler
|
||||
|
@ -388,8 +408,9 @@ ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
|
|||
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||
return generic_getxattr(dentry, name, buffer, size);
|
||||
|
||||
if (!btrfs_is_valid_xattr(name))
|
||||
return -EOPNOTSUPP;
|
||||
ret = btrfs_is_valid_xattr(name);
|
||||
if (ret)
|
||||
return ret;
|
||||
return __btrfs_getxattr(dentry->d_inode, name, buffer, size);
|
||||
}
|
||||
|
||||
|
@ -397,6 +418,7 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
|||
size_t size, int flags)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The permission on security.* and system.* is not checked
|
||||
|
@ -413,8 +435,9 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
|||
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||
return generic_setxattr(dentry, name, value, size, flags);
|
||||
|
||||
if (!btrfs_is_valid_xattr(name))
|
||||
return -EOPNOTSUPP;
|
||||
ret = btrfs_is_valid_xattr(name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
|
||||
return btrfs_set_prop(dentry->d_inode, name,
|
||||
|
@ -430,6 +453,7 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
|
|||
int btrfs_removexattr(struct dentry *dentry, const char *name)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(dentry->d_inode)->root;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The permission on security.* and system.* is not checked
|
||||
|
@ -446,8 +470,9 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
|
|||
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
|
||||
return generic_removexattr(dentry, name);
|
||||
|
||||
if (!btrfs_is_valid_xattr(name))
|
||||
return -EOPNOTSUPP;
|
||||
ret = btrfs_is_valid_xattr(name);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
|
||||
return btrfs_set_prop(dentry->d_inode, name,
|
||||
|
|
Loading…
Reference in a new issue