libext2fs: check ea value offset when loading

When reading extended attributes, check e_value_offs to make sure that
it starts in the value area and not the name area.  The attached test
case image will crash the kernel if it is mounted and you append more
than 4096 bytes of data to /a, due to insufficient validation.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
crypto
Darrick J. Wong 2014-09-11 13:17:44 -07:00 committed by Theodore Ts'o
parent f0770b16ef
commit 551ab6d8e0
5 changed files with 47 additions and 5 deletions

View File

@ -618,7 +618,7 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
size_t *nr_read)
{
struct ext2_xattr *x;
struct ext2_ext_attr_entry *entry;
struct ext2_ext_attr_entry *entry, *end;
const char *prefix;
unsigned int remain, prefix_len;
errcode_t err;
@ -629,6 +629,24 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
while (x->name)
x++;
/* find the end */
end = entries;
remain = storage_size;
while (remain >= sizeof(struct ext2_ext_attr_entry) &&
!EXT2_EXT_IS_LAST_ENTRY(end)) {
/* header eats this space */
remain -= sizeof(struct ext2_ext_attr_entry);
/* is attribute name valid? */
if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain)
return EXT2_ET_EA_BAD_NAME_LEN;
/* attribute len eats this space */
remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len);
end = EXT2_EXT_ATTR_NEXT(end);
}
entry = entries;
remain = storage_size;
while (remain >= sizeof(struct ext2_ext_attr_entry) &&
@ -638,10 +656,6 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
/* header eats this space */
remain -= sizeof(struct ext2_ext_attr_entry);
/* is attribute name valid? */
if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain)
return EXT2_ET_EA_BAD_NAME_LEN;
/* attribute len eats this space */
remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
@ -652,6 +666,11 @@ static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
if (entry->e_value_offs + entry->e_value_size > values_size)
return EXT2_ET_EA_BAD_VALUE_OFFSET;
if (entry->e_value_size > 0 &&
value_start + entry->e_value_offs <
(void *)end + sizeof(__u32))
return EXT2_ET_EA_BAD_VALUE_OFFSET;
/* e_value_block must be 0 in inode's ea */
if (entry->e_value_block != 0)
return EXT2_ET_BAD_EA_BLOCK_NUM;

View File

@ -0,0 +1,15 @@
Pass 1: Checking inodes, blocks, and sizes
Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes
Inode 12 extended attribute is corrupt (allocation collision). Clear? yes
Inode 13 extended attribute is corrupt (allocation collision). Clear? yes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks
Exit status is 1

View File

@ -0,0 +1,7 @@
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks
Exit status is 0

Binary file not shown.

View File

@ -0,0 +1 @@
extended attribute value conflicts with key