bcache: fix refcount underflow in bcache_device_free()
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>
This commit is contained in:
parent
46f5aa8806
commit
86da9f7367
@ -797,7 +797,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)
|
||||
@ -805,7 +807,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);
|
||||
|
Loading…
Reference in New Issue
Block a user