| From aca0fa34bdaba39bfddddba8ca70dba4782e8fe6 Mon Sep 17 00:00:00 2001 |
| From: Dave Kleikamp <shaggy@linux.vnet.ibm.com> |
| Date: Mon, 9 Aug 2010 15:57:38 -0500 |
| Subject: jfs: don't allow os2 xattr namespace overlap with others |
| |
| From: Dave Kleikamp <shaggy@linux.vnet.ibm.com> |
| |
| commit aca0fa34bdaba39bfddddba8ca70dba4782e8fe6 upstream. |
| |
| 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: Dave Kleikamp <shaggy@linux.vnet.ibm.com> |
| Reported-by: Sergey Vlasov <vsu@altlinux.ru> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| fs/jfs/xattr.c | 87 ++++++++++++++++++++++++--------------------------------- |
| 1 file changed, 38 insertions(+), 49 deletions(-) |
| |
| --- a/fs/jfs/xattr.c |
| +++ b/fs/jfs/xattr.c |
| @@ -86,46 +86,25 @@ struct ea_buffer { |
| #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 |
| * that are in a recognized namespace. If the attribute is not recognized, |
| * "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) |
| { |
| - /* |
| - * 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; |
| + return !is_known_namespace(ea->name); |
| } |
| |
| static inline int name_size(struct jfs_ea *ea) |
| @@ -764,13 +743,23 @@ static int can_set_xattr(struct inode *i |
| if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_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. |
| */ |
| if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && |
| strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && |
| - strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && |
| - strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) |
| + strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) |
| return -EOPNOTSUPP; |
| |
| return 0; |
| @@ -952,19 +941,8 @@ ssize_t __jfs_getxattr(struct inode *ino |
| int xattr_size; |
| ssize_t size; |
| int namelen = strlen(name); |
| - char *os2name = NULL; |
| 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); |
| |
| xattr_size = ea_get(inode, &ea_buf, 0); |
| @@ -1002,8 +980,6 @@ ssize_t __jfs_getxattr(struct inode *ino |
| out: |
| up_read(&JFS_IP(inode)->xattr_sem); |
| |
| - kfree(os2name); |
| - |
| return size; |
| } |
| |
| @@ -1012,6 +988,19 @@ ssize_t jfs_getxattr(struct dentry *dent |
| { |
| 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); |
| |
| return err; |