lkml.org 
[lkml]   [2018]   [Sep]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 3.16 31/63] ext4: add corruption check in ext4_xattr_set_entry()
    3.16.58-rc1 review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Theodore Ts'o <tytso@mit.edu>

    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>
    ---
    --- a/fs/ext4/xattr.c
    +++ b/fs/ext4/xattr.c
    @@ -610,14 +610,20 @@ static size_t ext4_xattr_free_space(stru
    }

    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)
    @@ -798,7 +804,7 @@ ext4_xattr_block_set(handle_t *handle, s
    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),
    @@ -851,7 +857,7 @@ ext4_xattr_block_set(handle_t *handle, s
    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)
    @@ -1021,7 +1027,7 @@ int ext4_xattr_ibody_inline_set(handle_t

    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)) {
    @@ -1033,7 +1039,7 @@ int ext4_xattr_ibody_inline_set(handle_t
    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;
    @@ -1059,7 +1065,7 @@ static int ext4_xattr_ibody_set(handle_t

    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));
    \
     
     \ /
      Last update: 2018-09-22 02:22    [W:2.359 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site