Skip to content

Commit

Permalink
ext4: add corruption check in ext4_xattr_set_entry()
Browse files Browse the repository at this point in the history
commit 5369a762c882c0b6e9599e4ebbb3a9ba9eee7e2d upstream.

In theory this should have been caught earlier when the xattr list was
verified, but in case it got missed, it's simple enough to add check
to make sure we don't overrun the xattr buffer.

This addresses CVE-2018-10879.

https://bugzilla.kernel.org/show_bug.cgi?id=200001

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
[bwh: Backported to 3.16:
 - Add inode parameter to ext4_xattr_set_entry() and update callers
 - Return -EIO instead of -EFSCORRUPTED on error
 - Adjust context]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Greg Hackmann <ghackmann@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
tytso authored and gregkh committed Oct 13, 2018
1 parent 5141d33 commit 912e35d
Showing 1 changed file with 14 additions and 8 deletions.
22 changes: 14 additions & 8 deletions fs/ext4/xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -637,14 +637,20 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
}

static int
ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s,
struct inode *inode)
{
struct ext4_xattr_entry *last;
struct ext4_xattr_entry *last, *next;
size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);

/* Compute min_offs and last. */
last = s->first;
for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
for (; !IS_LAST_ENTRY(last); last = next) {
next = EXT4_XATTR_NEXT(last);
if ((void *)next >= s->end) {
EXT4_ERROR_INODE(inode, "corrupted xattr entries");
return -EIO;
}
if (!last->e_value_block && last->e_value_size) {
size_t offs = le16_to_cpu(last->e_value_offs);
if (offs < min_offs)
Expand Down Expand Up @@ -825,7 +831,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
ce = NULL;
}
ea_bdebug(bs->bh, "modifying in-place");
error = ext4_xattr_set_entry(i, s);
error = ext4_xattr_set_entry(i, s, inode);
if (!error) {
if (!IS_LAST_ENTRY(s->first))
ext4_xattr_rehash(header(s->base),
Expand Down Expand Up @@ -877,7 +883,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode,
s->end = s->base + sb->s_blocksize;
}

error = ext4_xattr_set_entry(i, s);
error = ext4_xattr_set_entry(i, s, inode);
if (error == -EIO)
goto bad_block;
if (error)
Expand Down Expand Up @@ -1038,7 +1044,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,

if (EXT4_I(inode)->i_extra_isize == 0)
return -ENOSPC;
error = ext4_xattr_set_entry(i, s);
error = ext4_xattr_set_entry(i, s, inode);
if (error) {
if (error == -ENOSPC &&
ext4_has_inline_data(inode)) {
Expand All @@ -1050,7 +1056,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode,
error = ext4_xattr_ibody_find(inode, i, is);
if (error)
return error;
error = ext4_xattr_set_entry(i, s);
error = ext4_xattr_set_entry(i, s, inode);
}
if (error)
return error;
Expand All @@ -1076,7 +1082,7 @@ static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,

if (EXT4_I(inode)->i_extra_isize == 0)
return -ENOSPC;
error = ext4_xattr_set_entry(i, s);
error = ext4_xattr_set_entry(i, s, inode);
if (error)
return error;
header = IHDR(inode, ext4_raw_inode(&is->iloc));
Expand Down

0 comments on commit 912e35d

Please sign in to comment.