inode_detach_wb references the "main" bdi of the inode. With the recent change to move the bdi from the request_queue to the gendisk this causes a guaranteed use after free when using certain cgroup configurations. The big itself is older through as any non-default inode reference (e.g. an open file descriptor) could have injected this use after free even before that. Fixes: 52ebea749aae ("writeback: make backing_dev_info host cgroup-specific bdi_writebacks") Reported-by: Qian Cai <quic_qiancai@xxxxxxxxxxx> Signed-off-by: Christoph Hellwig <hch@xxxxxx> Tested-by: Qian Cai <quic_qiancai@xxxxxxxxxxx> --- block/genhd.c | 1 - fs/block_dev.c | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 9e60722e9ce7..3c1ca21ab2ee 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1051,7 +1051,6 @@ static void disk_release(struct device *dev) might_sleep(); - bdi_put(disk->bdi); if (MAJOR(dev->devt) == BLOCK_EXT_MAJOR) blk_free_ext_minor(MINOR(dev->devt)); disk_release_events(disk); diff --git a/fs/block_dev.c b/fs/block_dev.c index a2c3d11eda5e..a61273ff1dcf 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -826,11 +826,14 @@ static void init_once(void *data) static void bdev_evict_inode(struct inode *inode) { + struct block_device *bdev = I_BDEV(inode); + truncate_inode_pages_final(&inode->i_data); invalidate_inode_buffers(inode); /* is it needed here? */ clear_inode(inode); - /* Detach inode from wb early as bdi_put() may free bdi->wb */ inode_detach_wb(inode); + if (!bdev_is_partition(bdev)) + bdi_put(bdev->bd_disk->bdi); } static const struct super_operations bdev_sops = { -- 2.30.2