lkml.org 
[lkml]   [2019]   [Apr]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 127/134] staging: erofs: keep corrupted fs from crashing kernel in erofs_readdir()
    Date
    4.19-stable review patch.  If anyone has any objections, please let me know.

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

    From: Gao Xiang <gaoxiang25@huawei.com>

    commit 33bac912840fe64dbc15556302537dc6a17cac63 upstream.

    After commit 419d6efc50e9, kernel cannot be crashed in the namei
    path. However, corrupted nameoff can do harm in the process of
    readdir for scenerios without dm-verity as well. Fix it now.

    Fixes: 3aa8ec716e52 ("staging: erofs: add directory operations")
    Cc: <stable@vger.kernel.org> # 4.19+
    Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
    Reviewed-by: Chao Yu <yuchao0@huawei.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>


    ---
    drivers/staging/erofs/dir.c | 45 ++++++++++++++++++++++++--------------------
    1 file changed, 25 insertions(+), 20 deletions(-)

    --- a/drivers/staging/erofs/dir.c
    +++ b/drivers/staging/erofs/dir.c
    @@ -23,6 +23,21 @@ static const unsigned char erofs_filetyp
    [EROFS_FT_SYMLINK] = DT_LNK,
    };

    +static void debug_one_dentry(unsigned char d_type, const char *de_name,
    + unsigned int de_namelen)
    +{
    +#ifdef CONFIG_EROFS_FS_DEBUG
    + /* since the on-disk name could not have the trailing '\0' */
    + unsigned char dbg_namebuf[EROFS_NAME_LEN + 1];
    +
    + memcpy(dbg_namebuf, de_name, de_namelen);
    + dbg_namebuf[de_namelen] = '\0';
    +
    + debugln("found dirent %s de_len %u d_type %d", dbg_namebuf,
    + de_namelen, d_type);
    +#endif
    +}
    +
    static int erofs_fill_dentries(struct dir_context *ctx,
    void *dentry_blk, unsigned *ofs,
    unsigned nameoff, unsigned maxsize)
    @@ -33,14 +48,10 @@ static int erofs_fill_dentries(struct di
    de = dentry_blk + *ofs;
    while (de < end) {
    const char *de_name;
    - int de_namelen;
    + unsigned int de_namelen;
    unsigned char d_type;
    -#ifdef CONFIG_EROFS_FS_DEBUG
    - unsigned dbg_namelen;
    - unsigned char dbg_namebuf[EROFS_NAME_LEN];
    -#endif

    - if (unlikely(de->file_type < EROFS_FT_MAX))
    + if (de->file_type < EROFS_FT_MAX)
    d_type = erofs_filetype_table[de->file_type];
    else
    d_type = DT_UNKNOWN;
    @@ -48,26 +59,20 @@ static int erofs_fill_dentries(struct di
    nameoff = le16_to_cpu(de->nameoff);
    de_name = (char *)dentry_blk + nameoff;

    - de_namelen = unlikely(de + 1 >= end) ?
    - /* last directory entry */
    - strnlen(de_name, maxsize - nameoff) :
    - le16_to_cpu(de[1].nameoff) - nameoff;
    + /* the last dirent in the block? */
    + if (de + 1 >= end)
    + de_namelen = strnlen(de_name, maxsize - nameoff);
    + else
    + de_namelen = le16_to_cpu(de[1].nameoff) - nameoff;

    /* a corrupted entry is found */
    - if (unlikely(de_namelen < 0)) {
    + if (unlikely(nameoff + de_namelen > maxsize ||
    + de_namelen > EROFS_NAME_LEN)) {
    DBG_BUGON(1);
    return -EIO;
    }

    -#ifdef CONFIG_EROFS_FS_DEBUG
    - dbg_namelen = min(EROFS_NAME_LEN - 1, de_namelen);
    - memcpy(dbg_namebuf, de_name, dbg_namelen);
    - dbg_namebuf[dbg_namelen] = '\0';
    -
    - debugln("%s, found de_name %s de_len %d d_type %d", __func__,
    - dbg_namebuf, de_namelen, d_type);
    -#endif
    -
    + debug_one_dentry(d_type, de_name, de_namelen);
    if (!dir_emit(ctx, de_name, de_namelen,
    le64_to_cpu(de->nid), d_type))
    /* stoped by some reason */

    \
     
     \ /
      Last update: 2019-04-01 19:19    [W:4.133 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site