mm: backing-dev: Take a reference to the bdi in use to prevent UAF
KASAN reports a reproducible issue in the BDI handling code due to a
dereference of a previously freed pointer to 'struct backing_dev_info'
in bdi_unregister().
Because of a distinct lack of locking and/or reference taking,
blk_cleanup_queue() puts the final taken reference to the bdi, which
is then promptly freed by release_bdi(). However, del_gendisk() calls
bdi_unregister() after the fact, which then attempts to dereference
it causing the kernel to panic.
Bug: 182815710
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Change-Id: Iaf3dadf3b983a4b7d74d4e273fc676350cfc387f
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index cd607fb..fdae423 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -877,9 +877,13 @@ int bdi_register_va(struct backing_dev_info *bdi, const char *fmt, va_list args)
if (bdi->dev) /* The driver needs to use separate queues per device */
return 0;
+ bdi_get(bdi);
+
dev = device_create_vargs(bdi_class, NULL, MKDEV(0, 0), bdi, fmt, args);
- if (IS_ERR(dev))
+ if (IS_ERR(dev)) {
+ bdi_put(bdi);
return PTR_ERR(dev);
+ }
cgwb_bdi_register(bdi);
bdi->dev = dev;
@@ -959,6 +963,8 @@ void bdi_unregister(struct backing_dev_info *bdi)
put_device(bdi->owner);
bdi->owner = NULL;
}
+
+ bdi_put(bdi);
}
static void release_bdi(struct kref *ref)