aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Kleikamp <shaggy@linux.vnet.ibm.com>2010-08-09 15:57:38 -0500
committerWilly Tarreau <w@1wt.eu>2010-08-28 20:59:49 +0200
commit1f1a97c4a36ebe091c10b8819a6812e3194a748f (patch)
treec5d7d911328a5e14c12310174a8795698d7f453a
parent3aa199850f00529b4ec4126c2ef89ee682e28830 (diff)
downloadlinux-2.4-1f1a97c4a36ebe091c10b8819a6812e3194a748f.tar.gz
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: Dave Kleikamp <shaggy@linux.vnet.ibm.com> Reported-by: Sergey Vlasov <vsu@altlinux.ru> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> [WT: rediffed from 2.6 commit aca0fa34bdaba39bfddddba8ca70dba4782e8fe6] Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--fs/jfs/xattr.c70
1 files changed, 34 insertions, 36 deletions
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index aff116c6457522..706146772ca88d 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -89,33 +89,23 @@ struct ea_buffer {
#define XATTR_OS2_PREFIX "os2."
#define XATTR_OS2_PREFIX_LEN (sizeof (XATTR_OS2_PREFIX) - 1)
+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))
+ return 0;
+
+ return 1;
+}
+
/*
* 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;
- /*
- * 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)
@@ -657,8 +647,16 @@ static int can_set_xattr(struct inode *inode, const char *name,
if (IS_IMMUTABLE(inode) || IS_APPEND(inode) || S_ISLNK(inode->i_mode))
return -EPERM;
- if((strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) != 0) &&
- (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) != 0))
+ if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
+ /*
+ * 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;
+ }
+ else if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) != 0)
return -EOPNOTSUPP;
if (!S_ISREG(inode->i_mode) &&
@@ -834,23 +832,12 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
int xattr_size;
ssize_t size;
int namelen = strlen(name);
- char *os2name = NULL;
int rc;
char *value;
if ((rc = can_get_xattr(inode, name)))
return rc;
- 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;
- }
-
xattr_size = ea_get(inode, &ea_buf, 0);
if (xattr_size < 0) {
size = xattr_size;
@@ -883,8 +870,6 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
release:
ea_release(inode, &ea_buf);
out:
- if (os2name)
- kfree(os2name);
return size;
}
@@ -892,6 +877,19 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,
ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
size_t buf_size)
{
+ 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;
+ }
+
return __jfs_getxattr(dentry->d_inode, name, data, buf_size);
}