Skip to content

Commit e7793f2

Browse files
tytsogregkh
authored andcommitted
ext4: add extra checks to ext4_xattr_block_get()
commit 54dd0e0 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 <[email protected]> Cc: [email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 9703952 commit e7793f2

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

fs/ext4/xattr.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end,
196196
while (!IS_LAST_ENTRY(entry)) {
197197
u32 size = le32_to_cpu(entry->e_value_size);
198198

199-
if (size > INT_MAX)
199+
if (size > EXT4_XATTR_SIZE_MAX)
200200
return -EFSCORRUPTED;
201201

202202
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,
539539
if (error)
540540
goto cleanup;
541541
size = le32_to_cpu(entry->e_value_size);
542+
error = -ERANGE;
543+
if (unlikely(size > EXT4_XATTR_SIZE_MAX))
544+
goto cleanup;
542545
if (buffer) {
543-
error = -ERANGE;
544546
if (size > buffer_size)
545547
goto cleanup;
546548
if (entry->e_value_inum) {
@@ -549,8 +551,12 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
549551
if (error)
550552
goto cleanup;
551553
} else {
552-
memcpy(buffer, bh->b_data +
553-
le16_to_cpu(entry->e_value_offs), size);
554+
u16 offset = le16_to_cpu(entry->e_value_offs);
555+
void *p = bh->b_data + offset;
556+
557+
if (unlikely(p + size > end))
558+
goto cleanup;
559+
memcpy(buffer, p, size);
554560
}
555561
}
556562
error = size;
@@ -588,8 +594,10 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
588594
if (error)
589595
goto cleanup;
590596
size = le32_to_cpu(entry->e_value_size);
597+
error = -ERANGE;
598+
if (unlikely(size > EXT4_XATTR_SIZE_MAX))
599+
goto cleanup;
591600
if (buffer) {
592-
error = -ERANGE;
593601
if (size > buffer_size)
594602
goto cleanup;
595603
if (entry->e_value_inum) {
@@ -598,8 +606,12 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
598606
if (error)
599607
goto cleanup;
600608
} else {
601-
memcpy(buffer, (void *)IFIRST(header) +
602-
le16_to_cpu(entry->e_value_offs), size);
609+
u16 offset = le16_to_cpu(entry->e_value_offs);
610+
void *p = (void *)IFIRST(header) + offset;
611+
612+
if (unlikely(p + size > end))
613+
goto cleanup;
614+
memcpy(buffer, p, size);
603615
}
604616
}
605617
error = size;

fs/ext4/xattr.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ struct ext4_xattr_entry {
7070
EXT4_I(inode)->i_extra_isize))
7171
#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
7272

73+
/*
74+
* XATTR_SIZE_MAX is currently 64k, but for the purposes of checking
75+
* for file system consistency errors, we use a somewhat bigger value.
76+
* This allows XATTR_SIZE_MAX to grow in the future, but by using this
77+
* instead of INT_MAX for certain consistency checks, we don't need to
78+
* worry about arithmetic overflows. (Actually XATTR_SIZE_MAX is
79+
* defined in include/uapi/linux/limits.h, so changing it is going
80+
* not going to be trivial....)
81+
*/
82+
#define EXT4_XATTR_SIZE_MAX (1 << 24)
83+
7384
/*
7485
* The minimum size of EA value when you start storing it in an external inode
7586
* size of block - size of header - size of 1 entry - 4 null bytes

0 commit comments

Comments
 (0)