3.16.60-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o tytso@mit.edu
commit 9496005d6ca4cf8f5ee8f828165a8956872dc59d upstream.
Add some paranoia checks to make sure we don't stray beyond the end of the valid memory region containing ext4 xattr entries while we are scanning for a match.
Also rename the function to xattr_find_entry() since it is static and thus only used in fs/ext4/xattr.c
Signed-off-by: Theodore Ts'o tytso@mit.edu [bwh: Backported to 3.16: - Keep passing an explicit size to xattr_find_entry() - s/EFSCORRUPTED/EIO/]] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- fs/ext4/xattr.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-)
--- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -240,18 +240,23 @@ ext4_xattr_check_entry(struct ext4_xattr }
static int -ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index, - const char *name, size_t size, int sorted) +xattr_find_entry(struct inode *inode, struct ext4_xattr_entry **pentry, + void *end, int name_index, const char *name, size_t size, + int sorted) { - struct ext4_xattr_entry *entry; + struct ext4_xattr_entry *entry, *next; size_t name_len; int cmp = 1;
if (name == NULL) return -EINVAL; name_len = strlen(name); - entry = *pentry; - for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { + for (entry = *pentry; !IS_LAST_ENTRY(entry); entry = next) { + next = EXT4_XATTR_NEXT(entry); + if ((void *) next >= end) { + EXT4_ERROR_INODE(inode, "corrupted xattr entries"); + return -EIO; + } cmp = name_index - entry->e_name_index; if (!cmp) cmp = name_len - entry->e_name_len; @@ -273,6 +278,7 @@ ext4_xattr_block_get(struct inode *inode struct buffer_head *bh = NULL; struct ext4_xattr_entry *entry; size_t size; + void *end; int error; struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode);
@@ -298,7 +304,9 @@ bad_block: } ext4_xattr_cache_insert(ext4_mb_cache, bh); entry = BFIRST(bh); - error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); + end = bh->b_data + bh->b_size; + error = xattr_find_entry(inode, &entry, end, name_index, name, + bh->b_size, 1); if (error == -EIO) goto bad_block; if (error) @@ -342,8 +350,8 @@ ext4_xattr_ibody_get(struct inode *inode error = ext4_xattr_check_names(entry, end, entry); if (error) goto cleanup; - error = ext4_xattr_find_entry(&entry, name_index, name, - end - (void *)entry, 0); + error = xattr_find_entry(inode, &entry, end, name_index, name, + end - (void *)entry, 0); if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); @@ -761,8 +769,9 @@ ext4_xattr_block_find(struct inode *inod bs->s.first = BFIRST(bs->bh); bs->s.end = bs->bh->b_data + bs->bh->b_size; bs->s.here = bs->s.first; - error = ext4_xattr_find_entry(&bs->s.here, i->name_index, - i->name, bs->bh->b_size, 1); + error = xattr_find_entry(inode, &bs->s.here, bs->s.end, + i->name_index, i->name, + bs->bh->b_size, 1); if (error && error != -ENODATA) goto cleanup; bs->s.not_found = error; @@ -1007,9 +1016,9 @@ int ext4_xattr_ibody_find(struct inode * if (error) return error; /* Find the named attribute. */ - error = ext4_xattr_find_entry(&is->s.here, i->name_index, - i->name, is->s.end - - (void *)is->s.base, 0); + error = xattr_find_entry(inode, &is->s.here, is->s.end, + i->name_index, i->name, + is->s.end - (void *)is->s.base, 0); if (error && error != -ENODATA) return error; is->s.not_found = error;