summaryrefslogtreecommitdiff
path: root/fs/ext4/xattr.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2018-03-30 20:04:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-24 09:36:31 +0200
commite7793f2a2ac85f912690a69f7964907e31731ae7 (patch)
tree3f826f3469cc1c1b7f92a958139a41dbe9414944 /fs/ext4/xattr.c
parent9703952178f1412b7a74e170298d58e96c53152f (diff)
ext4: add extra checks to ext4_xattr_block_get()
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> Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ext4/xattr.c')
-rw-r--r--fs/ext4/xattr.c26
1 files changed, 19 insertions, 7 deletions
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 88544d6f2cb3..1718354e6322 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -196,7 +196,7 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
while (!IS_LAST_ENTRY(entry)) {
u32 size = le32_to_cpu(entry->e_value_size);
- if (size > INT_MAX)
+ if (size > EXT4_XATTR_SIZE_MAX)
return -EFSCORRUPTED;
if (size != 0 && entry->e_value_inum == 0) {
@@ -539,8 +539,10 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
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;
if (size > buffer_size)
goto cleanup;
if (entry->e_value_inum) {
@@ -549,8 +551,12 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
if (error)
goto cleanup;
} else {
- memcpy(buffer, bh->b_data +
- le16_to_cpu(entry->e_value_offs), size);
+ u16 offset = le16_to_cpu(entry->e_value_offs);
+ void *p = bh->b_data + offset;
+
+ if (unlikely(p + size > end))
+ goto cleanup;
+ memcpy(buffer, p, size);
}
}
error = size;
@@ -588,8 +594,10 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
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;
if (size > buffer_size)
goto cleanup;
if (entry->e_value_inum) {
@@ -598,8 +606,12 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
if (error)
goto cleanup;
} else {
- memcpy(buffer, (void *)IFIRST(header) +
- le16_to_cpu(entry->e_value_offs), size);
+ u16 offset = le16_to_cpu(entry->e_value_offs);
+ void *p = (void *)IFIRST(header) + offset;
+
+ if (unlikely(p + size > end))
+ goto cleanup;
+ memcpy(buffer, p, size);
}
}
error = size;