3.16.60-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Theodore Ts'o <ty...@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 <ty...@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 <b...@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)

Reply via email to