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> [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>
This commit is contained in:
parent
9abd5e1cad
commit
5412a3ef79
|
@ -333,12 +333,18 @@ bad_block:
|
||||||
if (error)
|
if (error)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
size = le32_to_cpu(entry->e_value_size);
|
size = le32_to_cpu(entry->e_value_size);
|
||||||
|
error = -ERANGE;
|
||||||
|
if (unlikely(size > EXT4_XATTR_SIZE_MAX))
|
||||||
|
goto cleanup;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
error = -ERANGE;
|
u16 offset = le16_to_cpu(entry->e_value_offs);
|
||||||
|
void *p = bh->b_data + offset;
|
||||||
|
|
||||||
if (size > buffer_size)
|
if (size > buffer_size)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
|
if (unlikely(p + size > end))
|
||||||
size);
|
goto cleanup;
|
||||||
|
memcpy(buffer, p, size);
|
||||||
}
|
}
|
||||||
error = size;
|
error = size;
|
||||||
|
|
||||||
|
@ -376,12 +382,18 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
|
||||||
if (error)
|
if (error)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
size = le32_to_cpu(entry->e_value_size);
|
size = le32_to_cpu(entry->e_value_size);
|
||||||
|
error = -ERANGE;
|
||||||
|
if (unlikely(size > EXT4_XATTR_SIZE_MAX))
|
||||||
|
goto cleanup;
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
error = -ERANGE;
|
u16 offset = le16_to_cpu(entry->e_value_offs);
|
||||||
|
void *p = (void *)IFIRST(header) + offset;
|
||||||
|
|
||||||
if (size > buffer_size)
|
if (size > buffer_size)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
memcpy(buffer, (void *)IFIRST(header) +
|
if (unlikely(p + size > end))
|
||||||
le16_to_cpu(entry->e_value_offs), size);
|
goto cleanup;
|
||||||
|
memcpy(buffer, p, size);
|
||||||
}
|
}
|
||||||
error = size;
|
error = size;
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,17 @@ struct ext4_xattr_entry {
|
||||||
EXT4_I(inode)->i_extra_isize))
|
EXT4_I(inode)->i_extra_isize))
|
||||||
#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
|
#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 BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data))
|
||||||
#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr))
|
#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr))
|
||||||
#define BFIRST(bh) ENTRY(BHDR(bh)+1)
|
#define BFIRST(bh) ENTRY(BHDR(bh)+1)
|
||||||
|
|
Loading…
Reference in New Issue