3.16.60-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Theodore Ts'o tytso@mit.edu
commit 54dd0e0a1b255f115f8647fc6fb93273251b01b9 upstream.
Add explicit checks in ext4_xattr_block_get() just in case the e_value_offs and e_value_size fields in the the xattr block are corrupted in memory after the buffer_verified bit is set on the xattr block.
Signed-off-by: Theodore Ts'o tytso@mit.edu [bwh: Backported to 3.16: - Drop change to ext4_xattr_check_entries() which is only needed for the xattr-in-inode case - Adjust context, indentation] Signed-off-by: Ben Hutchings ben@decadent.org.uk --- --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -327,12 +327,18 @@ bad_block: if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); + error = -ERANGE; + if (unlikely(size > EXT4_XATTR_SIZE_MAX)) + goto cleanup; if (buffer) { - error = -ERANGE; + u16 offset = le16_to_cpu(entry->e_value_offs); + void *p = bh->b_data + offset; + if (size > buffer_size) goto cleanup; - memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), - size); + if (unlikely(p + size > end)) + goto cleanup; + memcpy(buffer, p, size); } error = size;
@@ -370,12 +376,18 @@ ext4_xattr_ibody_get(struct inode *inode if (error) goto cleanup; size = le32_to_cpu(entry->e_value_size); + error = -ERANGE; + if (unlikely(size > EXT4_XATTR_SIZE_MAX)) + goto cleanup; if (buffer) { - error = -ERANGE; + u16 offset = le16_to_cpu(entry->e_value_offs); + void *p = (void *)IFIRST(header) + offset; + if (size > buffer_size) goto cleanup; - memcpy(buffer, (void *)IFIRST(header) + - le16_to_cpu(entry->e_value_offs), size); + if (unlikely(p + size > end)) + goto cleanup; + memcpy(buffer, p, size); } error = size;
--- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h @@ -67,6 +67,17 @@ struct ext4_xattr_entry { EXT4_I(inode)->i_extra_isize)) #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
+/* + * XATTR_SIZE_MAX is currently 64k, but for the purposes of checking + * for file system consistency errors, we use a somewhat bigger value. + * This allows XATTR_SIZE_MAX to grow in the future, but by using this + * instead of INT_MAX for certain consistency checks, we don't need to + * worry about arithmetic overflows. (Actually XATTR_SIZE_MAX is + * defined in include/uapi/linux/limits.h, so changing it is going + * not going to be trivial....) + */ +#define EXT4_XATTR_SIZE_MAX (1 << 24) + #define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) #define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) #define BFIRST(bh) ENTRY(BHDR(bh)+1)