diff options
author | Dave Kleikamp <shaggy@linux.vnet.ibm.com> | 2010-08-09 16:57:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-10 18:33:09 -0400 |
commit | aca0fa34bdaba39bfddddba8ca70dba4782e8fe6 (patch) | |
tree | 201b3f01b7fa6f63faaf7bcb592fcd90f1fdb739 | |
parent | 2f9e825d3e0e2b407ae8f082de5c00afcf7378fb (diff) |
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>
-rw-r--r-- | fs/jfs/xattr.c | 87 |
1 files changed, 38 insertions, 49 deletions
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index fa96bbb26343..2d7f165d0f1d 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c | |||
@@ -86,46 +86,25 @@ struct ea_buffer { | |||
86 | #define EA_MALLOC 0x0008 | 86 | #define EA_MALLOC 0x0008 |
87 | 87 | ||
88 | 88 | ||
89 | static int is_known_namespace(const char *name) | ||
90 | { | ||
91 | if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && | ||
92 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && | ||
93 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | ||
94 | strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
95 | return false; | ||
96 | |||
97 | return true; | ||
98 | } | ||
99 | |||
89 | /* | 100 | /* |
90 | * These three routines are used to recognize on-disk extended attributes | 101 | * These three routines are used to recognize on-disk extended attributes |
91 | * that are in a recognized namespace. If the attribute is not recognized, | 102 | * that are in a recognized namespace. If the attribute is not recognized, |
92 | * "os2." is prepended to the name | 103 | * "os2." is prepended to the name |
93 | */ | 104 | */ |
94 | static inline int is_os2_xattr(struct jfs_ea *ea) | 105 | static int is_os2_xattr(struct jfs_ea *ea) |
95 | { | 106 | { |
96 | /* | 107 | return !is_known_namespace(ea->name); |
97 | * Check for "system." | ||
98 | */ | ||
99 | if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) && | ||
100 | !strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
101 | return false; | ||
102 | /* | ||
103 | * Check for "user." | ||
104 | */ | ||
105 | if ((ea->namelen >= XATTR_USER_PREFIX_LEN) && | ||
106 | !strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) | ||
107 | return false; | ||
108 | /* | ||
109 | * Check for "security." | ||
110 | */ | ||
111 | if ((ea->namelen >= XATTR_SECURITY_PREFIX_LEN) && | ||
112 | !strncmp(ea->name, XATTR_SECURITY_PREFIX, | ||
113 | XATTR_SECURITY_PREFIX_LEN)) | ||
114 | return false; | ||
115 | /* | ||
116 | * Check for "trusted." | ||
117 | */ | ||
118 | if ((ea->namelen >= XATTR_TRUSTED_PREFIX_LEN) && | ||
119 | !strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
120 | return false; | ||
121 | /* | ||
122 | * Add any other valid namespace prefixes here | ||
123 | */ | ||
124 | |||
125 | /* | ||
126 | * We assume it's OS/2's flat namespace | ||
127 | */ | ||
128 | return true; | ||
129 | } | 108 | } |
130 | 109 | ||
131 | static inline int name_size(struct jfs_ea *ea) | 110 | 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 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | 743 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) |
765 | return can_set_system_xattr(inode, name, value, value_len); | 744 | return can_set_system_xattr(inode, name, value, value_len); |
766 | 745 | ||
746 | if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) { | ||
747 | /* | ||
748 | * This makes sure that we aren't trying to set an | ||
749 | * attribute in a different namespace by prefixing it | ||
750 | * with "os2." | ||
751 | */ | ||
752 | if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN)) | ||
753 | return -EOPNOTSUPP; | ||
754 | return 0; | ||
755 | } | ||
756 | |||
767 | /* | 757 | /* |
768 | * Don't allow setting an attribute in an unknown namespace. | 758 | * Don't allow setting an attribute in an unknown namespace. |
769 | */ | 759 | */ |
770 | if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && | 760 | if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && |
771 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | 761 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && |
772 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && | 762 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) |
773 | strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) | ||
774 | return -EOPNOTSUPP; | 763 | return -EOPNOTSUPP; |
775 | 764 | ||
776 | return 0; | 765 | return 0; |
@@ -952,19 +941,8 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, | |||
952 | int xattr_size; | 941 | int xattr_size; |
953 | ssize_t size; | 942 | ssize_t size; |
954 | int namelen = strlen(name); | 943 | int namelen = strlen(name); |
955 | char *os2name = NULL; | ||
956 | char *value; | 944 | char *value; |
957 | 945 | ||
958 | if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { | ||
959 | os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, | ||
960 | GFP_KERNEL); | ||
961 | if (!os2name) | ||
962 | return -ENOMEM; | ||
963 | strcpy(os2name, name + XATTR_OS2_PREFIX_LEN); | ||
964 | name = os2name; | ||
965 | namelen -= XATTR_OS2_PREFIX_LEN; | ||
966 | } | ||
967 | |||
968 | down_read(&JFS_IP(inode)->xattr_sem); | 946 | down_read(&JFS_IP(inode)->xattr_sem); |
969 | 947 | ||
970 | xattr_size = ea_get(inode, &ea_buf, 0); | 948 | 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 | out: | 980 | out: |
1003 | up_read(&JFS_IP(inode)->xattr_sem); | 981 | up_read(&JFS_IP(inode)->xattr_sem); |
1004 | 982 | ||
1005 | kfree(os2name); | ||
1006 | |||
1007 | return size; | 983 | return size; |
1008 | } | 984 | } |
1009 | 985 | ||
@@ -1012,6 +988,19 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, | |||
1012 | { | 988 | { |
1013 | int err; | 989 | int err; |
1014 | 990 | ||
991 | if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { | ||
992 | /* | ||
993 | * skip past "os2." prefix | ||
994 | */ | ||
995 | name += XATTR_OS2_PREFIX_LEN; | ||
996 | /* | ||
997 | * Don't allow retrieving properly prefixed attributes | ||
998 | * by prepending them with "os2." | ||
999 | */ | ||
1000 | if (is_known_namespace(name)) | ||
1001 | return -EOPNOTSUPP; | ||
1002 | } | ||
1003 | |||
1015 | err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); | 1004 | err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); |
1016 | 1005 | ||
1017 | return err; | 1006 | return err; |