| From 3c3b04d10ff1811a27f86684ccd2f5ba6983211d Mon Sep 17 00:00:00 2001 |
| From: David Sterba <dsterba@suse.cz> |
| Date: Wed, 25 Mar 2015 19:26:41 +0100 |
| Subject: btrfs: don't accept bare namespace as a valid xattr |
| |
| From: David Sterba <dsterba@suse.cz> |
| |
| commit 3c3b04d10ff1811a27f86684ccd2f5ba6983211d 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=94291 |
| Reported-by: William Douglas <william.douglas@intel.com> |
| Signed-off-by: David Sterba <dsterba@suse.cz> |
| Signed-off-by: Chris Mason <clm@fb.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/xattr.c | 53 +++++++++++++++++++++++++++++++++++++++-------------- |
| 1 file changed, 39 insertions(+), 14 deletions(-) |
| |
| --- a/fs/btrfs/xattr.c |
| +++ b/fs/btrfs/xattr.c |
| @@ -364,22 +364,42 @@ const struct xattr_handler *btrfs_xattr_ |
| /* |
| * 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 *de |
| 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 |
| 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 |
| 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 |
| 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 *den |
| 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, |