The force_poll_sync debugfs file uses the driver's struct btusb_data as its private data. The file is created under hdev->debugfs and is removed only when the HCI device is released, while btusb_disconnect() frees btusb_data unconditionally. The HCI device can outlive the driver data, for example when an HCI socket still references it, so reading or writing the already opened file then dereferences freed memory: BUG: KASAN: slab-use-after-free in force_poll_sync_read+0x129/0x140 Read of size 1 at addr ffff88800cfb7038 ... Freed by task ...: kfree btusb_disconnect Remove the debugfs file before the private data is freed. debugfs_remove() waits for callers that are already inside the file operations, and any later access fails with -EIO instead of reaching the driver, so btusb_data can no longer be dereferenced after it is gone. Fixes: 800fe5ec302e ("Bluetooth: btusb: Add support for queuing during polling interval") Cc: stable@vger.kernel.org Co-developed-by: Bin Yu Signed-off-by: Bin Yu Co-developed-by: Cheng Wen Signed-off-by: Cheng Wen Signed-off-by: YuanZhe Liu <25031212351@stu.xidian.edu.cn> --- drivers/bluetooth/btusb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index dc7191bf4234..d928580512fa 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1066,6 +1066,8 @@ struct btusb_data { int (*disconnect)(struct hci_dev *hdev); int oob_wake_irq; /* irq for out-of-band wake-on-bt */ + + struct dentry *force_poll_sync_dentry; }; static void btusb_reset(struct hci_dev *hdev) @@ -4560,8 +4562,9 @@ static int btusb_probe(struct usb_interface *intf, usb_set_intfdata(intf, data); - debugfs_create_file("force_poll_sync", 0644, hdev->debugfs, data, - &force_poll_sync_fops); + data->force_poll_sync_dentry = + debugfs_create_file("force_poll_sync", 0644, hdev->debugfs, + data, &force_poll_sync_fops); return 0; @@ -4602,6 +4605,9 @@ static void btusb_disconnect(struct usb_interface *intf) if (!data) return; + debugfs_remove(data->force_poll_sync_dentry); + data->force_poll_sync_dentry = NULL; + hdev = data->hdev; usb_set_intfdata(data->intf, NULL); -- 2.34.1