Commit dfca7b21 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Linus Torvalds

[PATCH] xattr: re-introduce validity check before xattr cache insert

* ext[23]_xattr_list():

  - Before inserting an xattr block into the cache, make sure that the
    block is not corrupted.  The check got moved after inserting into the
    cache in the xattr consolidation patches, so corrupted blocks could become
    visible to cache users.

  - Take a variable out of the loop that calls the ->list handlers.

* A few cosmetic changes.
Signed-off-by: default avatarAndreas Gruenbacher <agruen@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent f25ce515
...@@ -400,7 +400,7 @@ ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size, ...@@ -400,7 +400,7 @@ ext2_xattr_list_acl_access(struct inode *inode, char *list, size_t list_size,
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
return 0; return 0;
if (list && (size <= list_size)) if (list && size <= list_size)
memcpy(list, XATTR_NAME_ACL_ACCESS, size); memcpy(list, XATTR_NAME_ACL_ACCESS, size);
return size; return size;
} }
...@@ -413,7 +413,7 @@ ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size, ...@@ -413,7 +413,7 @@ ext2_xattr_list_acl_default(struct inode *inode, char *list, size_t list_size,
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
return 0; return 0;
if (list && (size <= list_size)) if (list && size <= list_size)
memcpy(list, XATTR_NAME_ACL_DEFAULT, size); memcpy(list, XATTR_NAME_ACL_DEFAULT, size);
return size; return size;
} }
......
...@@ -270,8 +270,8 @@ ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ...@@ -270,8 +270,8 @@ ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext2_xattr_entry *entry; struct ext2_xattr_entry *entry;
size_t total_size = 0; char *end;
char *buf, *end; size_t rest = buffer_size;
int error; int error;
ea_idebug(inode, "buffer=%p, buffer_size=%ld", ea_idebug(inode, "buffer=%p, buffer_size=%ld",
...@@ -298,36 +298,39 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", ...@@ -298,36 +298,39 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
goto cleanup; goto cleanup;
} }
/* check the on-disk data structure */
entry = FIRST_ENTRY(bh);
while (!IS_LAST_ENTRY(entry)) {
struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry);
if ((char *)next >= end)
goto bad_block;
entry = next;
}
if (ext2_xattr_cache_insert(bh)) if (ext2_xattr_cache_insert(bh))
ea_idebug(inode, "cache insert failed"); ea_idebug(inode, "cache insert failed");
/* list the attribute names */ /* list the attribute names */
buf = buffer;
for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
entry = EXT2_XATTR_NEXT(entry)) { entry = EXT2_XATTR_NEXT(entry)) {
struct xattr_handler *handler; struct xattr_handler *handler =
struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); ext2_xattr_handler(entry->e_name_index);
if ((char *)next >= end)
goto bad_block;
handler = ext2_xattr_handler(entry->e_name_index);
if (handler) { if (handler) {
size_t size = handler->list(inode, buf, buffer_size, size_t size = handler->list(inode, buffer, rest,
entry->e_name, entry->e_name,
entry->e_name_len); entry->e_name_len);
if (buf) { if (buffer) {
if (size > buffer_size) { if (size > rest) {
error = -ERANGE; error = -ERANGE;
goto cleanup; goto cleanup;
} }
buf += size; buffer += size;
buffer_size -= size;
} }
total_size += size; rest -= size;
} }
} }
error = total_size; error = buffer_size - rest; /* total size */
cleanup: cleanup:
brelse(bh); brelse(bh);
......
...@@ -17,7 +17,7 @@ ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size, ...@@ -17,7 +17,7 @@ ext2_xattr_security_list(struct inode *inode, char *list, size_t list_size,
const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1; const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
const size_t total_len = prefix_len + name_len + 1; const size_t total_len = prefix_len + name_len + 1;
if (list && (total_len <= list_size)) { if (list && total_len <= list_size) {
memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len); memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0'; list[prefix_len + name_len] = '\0';
......
...@@ -24,7 +24,7 @@ ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, ...@@ -24,7 +24,7 @@ ext2_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return 0; return 0;
if (list && (total_len <= list_size)) { if (list && total_len <= list_size) {
memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len); memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0'; list[prefix_len + name_len] = '\0';
......
...@@ -23,7 +23,7 @@ ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size, ...@@ -23,7 +23,7 @@ ext2_xattr_user_list(struct inode *inode, char *list, size_t list_size,
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(inode->i_sb, XATTR_USER))
return 0; return 0;
if (list && (total_len <= list_size)) { if (list && total_len <= list_size) {
memcpy(list, XATTR_USER_PREFIX, prefix_len); memcpy(list, XATTR_USER_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len); memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0'; list[prefix_len + name_len] = '\0';
......
...@@ -423,7 +423,7 @@ ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len, ...@@ -423,7 +423,7 @@ ext3_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
return 0; return 0;
if (list && (size <= list_len)) if (list && size <= list_len)
memcpy(list, XATTR_NAME_ACL_ACCESS, size); memcpy(list, XATTR_NAME_ACL_ACCESS, size);
return size; return size;
} }
...@@ -436,7 +436,7 @@ ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len, ...@@ -436,7 +436,7 @@ ext3_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
if (!test_opt(inode->i_sb, POSIX_ACL)) if (!test_opt(inode->i_sb, POSIX_ACL))
return 0; return 0;
if (list && (size <= list_len)) if (list && size <= list_len)
memcpy(list, XATTR_NAME_ACL_DEFAULT, size); memcpy(list, XATTR_NAME_ACL_DEFAULT, size);
return size; return size;
} }
......
...@@ -267,8 +267,8 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ...@@ -267,8 +267,8 @@ ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{ {
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
struct ext3_xattr_entry *entry; struct ext3_xattr_entry *entry;
size_t total_size = 0; char *end;
char *buf, *end; size_t rest = buffer_size;
int error; int error;
ea_idebug(inode, "buffer=%p, buffer_size=%ld", ea_idebug(inode, "buffer=%p, buffer_size=%ld",
...@@ -295,36 +295,39 @@ bad_block: ext3_error(inode->i_sb, "ext3_xattr_list", ...@@ -295,36 +295,39 @@ bad_block: ext3_error(inode->i_sb, "ext3_xattr_list",
goto cleanup; goto cleanup;
} }
/* check the on-disk data structure */
entry = FIRST_ENTRY(bh);
while (!IS_LAST_ENTRY(entry)) {
struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(entry);
if ((char *)next >= end)
goto bad_block;
entry = next;
}
if (ext3_xattr_cache_insert(bh)) if (ext3_xattr_cache_insert(bh))
ea_idebug(inode, "cache insert failed"); ea_idebug(inode, "cache insert failed");
/* list the attribute names */ /* list the attribute names */
buf = buffer;
for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
entry = EXT3_XATTR_NEXT(entry)) { entry = EXT3_XATTR_NEXT(entry)) {
struct xattr_handler *handler; struct xattr_handler *handler =
struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(entry); ext3_xattr_handler(entry->e_name_index);
if ((char *)next >= end)
goto bad_block;
handler = ext3_xattr_handler(entry->e_name_index);
if (handler) { if (handler) {
size_t size = handler->list(inode, buf, buffer_size, size_t size = handler->list(inode, buffer, rest,
entry->e_name, entry->e_name,
entry->e_name_len); entry->e_name_len);
if (buf) { if (buffer) {
if (size > buffer_size) { if (size > rest) {
error = -ERANGE; error = -ERANGE;
goto cleanup; goto cleanup;
} }
buf += size; buffer += size;
buffer_size -= size;
} }
total_size += size; rest -= size;
} }
} }
error = total_size; error = buffer_size - rest; /* total size */
cleanup: cleanup:
brelse(bh); brelse(bh);
......
...@@ -19,7 +19,7 @@ ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size, ...@@ -19,7 +19,7 @@ ext3_xattr_security_list(struct inode *inode, char *list, size_t list_size,
const size_t total_len = prefix_len + name_len + 1; const size_t total_len = prefix_len + name_len + 1;
if (list && (total_len <= list_size)) { if (list && total_len <= list_size) {
memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len); memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0'; list[prefix_len + name_len] = '\0';
......
...@@ -25,7 +25,7 @@ ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size, ...@@ -25,7 +25,7 @@ ext3_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return 0; return 0;
if (list && (total_len <= list_size)) { if (list && total_len <= list_size) {
memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len); memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0'; list[prefix_len + name_len] = '\0';
......
...@@ -25,7 +25,7 @@ ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size, ...@@ -25,7 +25,7 @@ ext3_xattr_user_list(struct inode *inode, char *list, size_t list_size,
if (!test_opt(inode->i_sb, XATTR_USER)) if (!test_opt(inode->i_sb, XATTR_USER))
return 0; return 0;
if (list && (total_len <= list_size)) { if (list && total_len <= list_size) {
memcpy(list, XATTR_USER_PREFIX, prefix_len); memcpy(list, XATTR_USER_PREFIX, prefix_len);
memcpy(list+prefix_len, name, name_len); memcpy(list+prefix_len, name, name_len);
list[prefix_len + name_len] = '\0'; list[prefix_len + name_len] = '\0';
......
...@@ -352,7 +352,8 @@ sys_fremovexattr(int fd, char __user *name) ...@@ -352,7 +352,8 @@ sys_fremovexattr(int fd, char __user *name)
} }
static const char *strcmp_prefix(const char *a, const char *a_prefix) static const char *
strcmp_prefix(const char *a, const char *a_prefix)
{ {
while (*a_prefix && *a == *a_prefix) { while (*a_prefix && *a == *a_prefix) {
a++; a++;
......
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