1 ext4: limit xattr size to INT_MAX
3 From: Eric Biggers <ebiggers@google.com>
5 ext4 isn't validating the sizes of xattrs where the value of the xattr
6 is stored in an external inode. This is problematic because
7 ->e_value_size is a u32, but ext4_xattr_get() returns an int. A very
8 large size is misinterpreted as an error code, which ext4_get_acl()
9 translates into a bogus ERR_PTR() for which IS_ERR() returns false,
12 Fix this by validating that all xattrs are <= INT_MAX bytes. Also add
13 explicit checks in ext4_xattr_block_get() and ext4_xattr_ibody_get()
14 just in case the xattr block is corrupted in memory after it is
17 This issue has been assigned CVE-2018-1095.
19 https://bugzilla.kernel.org/show_bug.cgi?id=199185
20 https://bugzilla.redhat.com/show_bug.cgi?id=1560793
22 Reported-by: Wen Xu <wen.xu@gatech.edu>
23 Signed-off-by: Eric Biggers <ebiggers@google.com>
24 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
25 Cc: stable@vger.kernel.org
26 Fixes: e50e5129f384 ("ext4: xattr-in-inode support")
28 fs/ext4/xattr.c | 14 +++++++++++---
29 1 file changed, 11 insertions(+), 3 deletions(-)
31 diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
32 index 63656dbafdc4..d2a9b078e121 100644
35 @@ -195,10 +195,14 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
37 /* Check the values */
38 while (!IS_LAST_ENTRY(entry)) {
39 + u32 size = le32_to_cpu(entry->e_value_size);
42 + return -EFSCORRUPTED;
44 if (entry->e_value_size != 0 &&
45 entry->e_value_inum == 0) {
46 u16 offs = le16_to_cpu(entry->e_value_offs);
47 - u32 size = le32_to_cpu(entry->e_value_size);
51 @@ -523,8 +527,10 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
54 size = le32_to_cpu(entry->e_value_size);
56 + if (unlikely(size > INT_MAX))
60 if (size > buffer_size)
62 if (entry->e_value_inum) {
63 @@ -572,8 +578,10 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
66 size = le32_to_cpu(entry->e_value_size);
68 + if (unlikely(size > INT_MAX))
72 if (size > buffer_size)
74 if (entry->e_value_inum) {