Skip to content

Commit 86da9f7

Browse files
Coly Liaxboe
authored andcommitted
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 <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 46f5aa8 commit 86da9f7

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

drivers/md/bcache/super.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -797,15 +797,18 @@ static void bcache_device_free(struct bcache_device *d)
797797
bcache_device_detach(d);
798798

799799
if (disk) {
800-
if (disk->flags & GENHD_FL_UP)
800+
bool disk_added = (disk->flags & GENHD_FL_UP) != 0;
801+
802+
if (disk_added)
801803
del_gendisk(disk);
802804

803805
if (disk->queue)
804806
blk_cleanup_queue(disk->queue);
805807

806808
ida_simple_remove(&bcache_device_idx,
807809
first_minor_to_idx(disk->first_minor));
808-
put_disk(disk);
810+
if (disk_added)
811+
put_disk(disk);
809812
}
810813

811814
bioset_exit(&d->bio_split);

0 commit comments

Comments
 (0)