Commit aca0fa34 authored by Dave Kleikamp's avatar Dave Kleikamp Committed by Linus Torvalds

jfs: don't allow os2 xattr namespace overlap with others

It's currently possible to bypass xattr namespace access rules by
prefixing valid xattr names with "os2.", since the os2 namespace stores
extended attributes in a legacy format with no prefix.

This patch adds checking to deny access to any valid namespace prefix
following "os2.".
Signed-off-by: default avatarDave Kleikamp <shaggy@linux.vnet.ibm.com>
Reported-by: default avatarSergey Vlasov <vsu@altlinux.ru>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2f9e825d
...@@ -86,46 +86,25 @@ struct ea_buffer { ...@@ -86,46 +86,25 @@ struct ea_buffer {
#define EA_MALLOC 0x0008 #define EA_MALLOC 0x0008
static int is_known_namespace(const char *name)
{
if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) &&
strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
return false;
return true;
}
/* /*
* These three routines are used to recognize on-disk extended attributes * These three routines are used to recognize on-disk extended attributes
* that are in a recognized namespace. If the attribute is not recognized, * that are in a recognized namespace. If the attribute is not recognized,
* "os2." is prepended to the name * "os2." is prepended to the name
*/ */
static inline int is_os2_xattr(struct jfs_ea *ea) static int is_os2_xattr(struct jfs_ea *ea)
{ {
/* return !is_known_namespace(ea->name);
* Check for "system."
*/
if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
return false;
/*
* Check for "user."
*/
if ((ea->namelen >= XATTR_USER_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
return false;
/*
* Check for "security."
*/
if ((ea->namelen >= XATTR_SECURITY_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN))
return false;
/*
* Check for "trusted."
*/
if ((ea->namelen >= XATTR_TRUSTED_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
return false;
/*
* Add any other valid namespace prefixes here
*/
/*
* We assume it's OS/2's flat namespace
*/
return true;
} }
static inline int name_size(struct jfs_ea *ea) static inline int name_size(struct jfs_ea *ea)
...@@ -764,13 +743,23 @@ static int can_set_xattr(struct inode *inode, const char *name, ...@@ -764,13 +743,23 @@ static int can_set_xattr(struct inode *inode, const char *name,
if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
return can_set_system_xattr(inode, name, value, value_len); return can_set_system_xattr(inode, name, value, value_len);
if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) {
/*
* This makes sure that we aren't trying to set an
* attribute in a different namespace by prefixing it
* with "os2."
*/
if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN))
return -EOPNOTSUPP;
return 0;
}
/* /*
* Don't allow setting an attribute in an unknown namespace. * Don't allow setting an attribute in an unknown namespace.
*/ */
if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))
return -EOPNOTSUPP; return -EOPNOTSUPP;
return 0; return 0;
...@@ -952,19 +941,8 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, ...@@ -952,19 +941,8 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
int xattr_size; int xattr_size;
ssize_t size; ssize_t size;
int namelen = strlen(name); int namelen = strlen(name);
char *os2name = NULL;
char *value; char *value;
if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,
GFP_KERNEL);
if (!os2name)
return -ENOMEM;
strcpy(os2name, name + XATTR_OS2_PREFIX_LEN);
name = os2name;
namelen -= XATTR_OS2_PREFIX_LEN;
}
down_read(&JFS_IP(inode)->xattr_sem); down_read(&JFS_IP(inode)->xattr_sem);
xattr_size = ea_get(inode, &ea_buf, 0); xattr_size = ea_get(inode, &ea_buf, 0);
...@@ -1002,8 +980,6 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, ...@@ -1002,8 +980,6 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
out: out:
up_read(&JFS_IP(inode)->xattr_sem); up_read(&JFS_IP(inode)->xattr_sem);
kfree(os2name);
return size; return size;
} }
...@@ -1012,6 +988,19 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, ...@@ -1012,6 +988,19 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
{ {
int err; int err;
if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
/*
* skip past "os2." prefix
*/
name += XATTR_OS2_PREFIX_LEN;
/*
* Don't allow retrieving properly prefixed attributes
* by prepending them with "os2."
*/
if (is_known_namespace(name))
return -EOPNOTSUPP;
}
err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); err = __jfs_getxattr(dentry->d_inode, name, data, buf_size);
return err; return err;
......
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