3.16.60-rc1 review patch. If anyone has any objections, please let me know.
------------------ From: Theodore Ts'o <ty...@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 <ty...@mit.edu> [bwh: Backported to 3.16: - Keep passing an explicit size to xattr_find_entry() - s/EFSCORRUPTED/EIO/]] Signed-off-by: Ben Hutchings <b...@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;