lkml.org 
[lkml]   [2020]   [Jun]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.4 139/261] bcache: fix refcount underflow in bcache_device_free()
    Date
    From: Coly Li <colyli@suse.de>

    [ Upstream commit 86da9f736740eba602389908574dfbb0f517baa5 ]

    The problematic code piece in bcache_device_free() is,

    785 static void bcache_device_free(struct bcache_device *d)
    786 {
    787 struct gendisk *disk = d->disk;
    [snipped]
    799 if (disk) {
    800 if (disk->flags & GENHD_FL_UP)
    801 del_gendisk(disk);
    802
    803 if (disk->queue)
    804 blk_cleanup_queue(disk->queue);
    805
    806 ida_simple_remove(&bcache_device_idx,
    807 first_minor_to_idx(disk->first_minor));
    808 put_disk(disk);
    809 }
    [snipped]
    816 }

    At line 808, put_disk(disk) may encounter kobject refcount of 'disk'
    being underflow.

    Here is how to reproduce the issue,
    - Attche the backing device to a cache device and do random write to
    make the cache being dirty.
    - Stop the bcache device while the cache device has dirty data of the
    backing device.
    - Only register the backing device back, NOT register cache device.
    - The bcache device node /dev/bcache0 won't show up, because backing
    device waits for the cache device shows up for the missing dirty
    data.
    - Now echo 1 into /sys/fs/bcache/pendings_cleanup, to stop the pending
    backing device.
    - After the pending backing device stopped, use 'dmesg' to check kernel
    message, a use-after-free warning from KASA reported the refcount of
    kobject linked to the 'disk' is underflow.

    The dropping refcount at line 808 in the above code piece is added by
    add_disk(d->disk) in bch_cached_dev_run(). But in the above condition
    the cache device is not registered, bch_cached_dev_run() has no chance
    to be called and the refcount is not added. The put_disk() for a non-
    added refcount of gendisk kobject triggers a underflow warning.

    This patch checks whether GENHD_FL_UP is set in disk->flags, if it is
    not set then the bcache device was not added, don't call put_disk()
    and the the underflow issue can be avoided.

    Signed-off-by: Coly Li <colyli@suse.de>
    Signed-off-by: Jens Axboe <axboe@kernel.dk>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    drivers/md/bcache/super.c | 7 +++++--
    1 file changed, 5 insertions(+), 2 deletions(-)

    diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
    index 658b0f4a01f5..68901745eb20 100644
    --- a/drivers/md/bcache/super.c
    +++ b/drivers/md/bcache/super.c
    @@ -789,7 +789,9 @@ static void bcache_device_free(struct bcache_device *d)
    bcache_device_detach(d);

    if (disk) {
    - if (disk->flags & GENHD_FL_UP)
    + bool disk_added = (disk->flags & GENHD_FL_UP) != 0;
    +
    + if (disk_added)
    del_gendisk(disk);

    if (disk->queue)
    @@ -797,7 +799,8 @@ static void bcache_device_free(struct bcache_device *d)

    ida_simple_remove(&bcache_device_idx,
    first_minor_to_idx(disk->first_minor));
    - put_disk(disk);
    + if (disk_added)
    + put_disk(disk);
    }

    bioset_exit(&d->bio_split);
    --
    2.25.1


    \
     
     \ /
      Last update: 2020-06-19 18:05    [W:4.008 / U:0.540 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site