lkml.org 
[lkml]   [2021]   [Nov]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 24/35] regmap: Fix possible double-free in regcache_rbtree_exit()
    Date
    From: Yang Yingliang <yangyingliang@huawei.com>

    commit 55e6d8037805b3400096d621091dfbf713f97e83 upstream.

    In regcache_rbtree_insert_to_block(), when 'present' realloc failed,
    the 'blk' which is supposed to assign to 'rbnode->block' will be freed,
    so 'rbnode->block' points a freed memory, in the error handling path of
    regcache_rbtree_init(), 'rbnode->block' will be freed again in
    regcache_rbtree_exit(), KASAN will report double-free as follows:

    BUG: KASAN: double-free or invalid-free in kfree+0xce/0x390
    Call Trace:
    slab_free_freelist_hook+0x10d/0x240
    kfree+0xce/0x390
    regcache_rbtree_exit+0x15d/0x1a0
    regcache_rbtree_init+0x224/0x2c0
    regcache_init+0x88d/0x1310
    __regmap_init+0x3151/0x4a80
    __devm_regmap_init+0x7d/0x100
    madera_spi_probe+0x10f/0x333 [madera_spi]
    spi_probe+0x183/0x210
    really_probe+0x285/0xc30

    To fix this, moving up the assignment of rbnode->block to immediately after
    the reallocation has succeeded so that the data structure stays valid even
    if the second reallocation fails.

    Reported-by: Hulk Robot <hulkci@huawei.com>
    Fixes: 3f4ff561bc88b ("regmap: rbtree: Make cache_present bitmap per node")
    Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
    Link: https://lore.kernel.org/r/20211012023735.1632786-1-yangyingliang@huawei.com
    Signed-off-by: Mark Brown <broonie@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/base/regmap/regcache-rbtree.c | 7 +++----
    1 file changed, 3 insertions(+), 4 deletions(-)

    --- a/drivers/base/regmap/regcache-rbtree.c
    +++ b/drivers/base/regmap/regcache-rbtree.c
    @@ -295,14 +295,14 @@ static int regcache_rbtree_insert_to_blo
    if (!blk)
    return -ENOMEM;

    + rbnode->block = blk;
    +
    if (BITS_TO_LONGS(blklen) > BITS_TO_LONGS(rbnode->blklen)) {
    present = krealloc(rbnode->cache_present,
    BITS_TO_LONGS(blklen) * sizeof(*present),
    GFP_KERNEL);
    - if (!present) {
    - kfree(blk);
    + if (!present)
    return -ENOMEM;
    - }

    memset(present + BITS_TO_LONGS(rbnode->blklen), 0,
    (BITS_TO_LONGS(blklen) - BITS_TO_LONGS(rbnode->blklen))
    @@ -319,7 +319,6 @@ static int regcache_rbtree_insert_to_blo
    }

    /* update the rbnode block, its size and the base register */
    - rbnode->block = blk;
    rbnode->blklen = blklen;
    rbnode->base_reg = base_reg;
    rbnode->cache_present = present;

    \
     
     \ /
      Last update: 2021-11-01 10:26    [W:4.088 / U:0.780 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site