Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: vhci: Prevent use-after-free by removing debugfs files early

Move the creation of debugfs files into a dedicated function, and ensure
they are explicitly removed during vhci_release(), before associated
data structures are freed.

Previously, debugfs files such as "force_suspend", "force_wakeup", and
others were created under hdev->debugfs but not removed in
vhci_release(). Since vhci_release() frees the backing vhci_data
structure, any access to these files after release would result in
use-after-free errors.

Although hdev->debugfs is later freed in hci_release_dev(), user can
access files after vhci_data is freed but before hdev->debugfs is
released.

Fixes: ab4e4380d4e1 ("Bluetooth: Add vhci devcoredump support")
Signed-off-by: Ivan Pravdin <ipravdin.official@gmail.com>
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Ivan Pravdin and committed by
Luiz Augusto von Dentz
28010791 5189446b

+41 -16
+41 -16
drivers/bluetooth/hci_vhci.c
··· 380 380 .write = force_devcd_write, 381 381 }; 382 382 383 + static void vhci_debugfs_init(struct vhci_data *data) 384 + { 385 + struct hci_dev *hdev = data->hdev; 386 + 387 + debugfs_create_file("force_suspend", 0644, hdev->debugfs, data, 388 + &force_suspend_fops); 389 + 390 + debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data, 391 + &force_wakeup_fops); 392 + 393 + if (IS_ENABLED(CONFIG_BT_MSFTEXT)) 394 + debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data, 395 + &msft_opcode_fops); 396 + 397 + if (IS_ENABLED(CONFIG_BT_AOSPEXT)) 398 + debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data, 399 + &aosp_capable_fops); 400 + 401 + debugfs_create_file("force_devcoredump", 0644, hdev->debugfs, data, 402 + &force_devcoredump_fops); 403 + } 404 + 383 405 static int __vhci_create_device(struct vhci_data *data, __u8 opcode) 384 406 { 385 407 struct hci_dev *hdev; ··· 456 434 return -EBUSY; 457 435 } 458 436 459 - debugfs_create_file("force_suspend", 0644, hdev->debugfs, data, 460 - &force_suspend_fops); 461 - 462 - debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data, 463 - &force_wakeup_fops); 464 - 465 - if (IS_ENABLED(CONFIG_BT_MSFTEXT)) 466 - debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data, 467 - &msft_opcode_fops); 468 - 469 - if (IS_ENABLED(CONFIG_BT_AOSPEXT)) 470 - debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data, 471 - &aosp_capable_fops); 472 - 473 - debugfs_create_file("force_devcoredump", 0644, hdev->debugfs, data, 474 - &force_devcoredump_fops); 437 + if (!IS_ERR_OR_NULL(hdev->debugfs)) 438 + vhci_debugfs_init(data); 475 439 476 440 hci_skb_pkt_type(skb) = HCI_VENDOR_PKT; 477 441 ··· 659 651 return 0; 660 652 } 661 653 654 + static void vhci_debugfs_remove(struct hci_dev *hdev) 655 + { 656 + debugfs_lookup_and_remove("force_suspend", hdev->debugfs); 657 + 658 + debugfs_lookup_and_remove("force_wakeup", hdev->debugfs); 659 + 660 + if (IS_ENABLED(CONFIG_BT_MSFTEXT)) 661 + debugfs_lookup_and_remove("msft_opcode", hdev->debugfs); 662 + 663 + if (IS_ENABLED(CONFIG_BT_AOSPEXT)) 664 + debugfs_lookup_and_remove("aosp_capable", hdev->debugfs); 665 + 666 + debugfs_lookup_and_remove("force_devcoredump", hdev->debugfs); 667 + } 668 + 662 669 static int vhci_release(struct inode *inode, struct file *file) 663 670 { 664 671 struct vhci_data *data = file->private_data; ··· 685 662 hdev = data->hdev; 686 663 687 664 if (hdev) { 665 + if (!IS_ERR_OR_NULL(hdev->debugfs)) 666 + vhci_debugfs_remove(hdev); 688 667 hci_unregister_dev(hdev); 689 668 hci_free_dev(hdev); 690 669 }