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

Bluetooth: msft: fix slab-use-after-free in msft_do_close()

Tying the msft->data lifetime to hdev by freeing it in
hci_release_dev() to fix the following case:

[use]
msft_do_close()
msft = hdev->msft_data;
if (!msft) ...(1) <- passed.
return;
mutex_lock(&msft->filter_lock); ...(4) <- used after freed.

[free]
msft_unregister()
msft = hdev->msft_data;
hdev->msft_data = NULL; ...(2)
kfree(msft); ...(3) <- msft is freed.

==================================================================
BUG: KASAN: slab-use-after-free in __mutex_lock_common
kernel/locking/mutex.c:587 [inline]
BUG: KASAN: slab-use-after-free in __mutex_lock+0x8f/0xc30
kernel/locking/mutex.c:752
Read of size 8 at addr ffff888106cbbca8 by task kworker/u5:2/309

Fixes: bf6a4e30ffbd ("Bluetooth: disable advertisement filters during suspend")
Signed-off-by: Sungwoo Kim <iam@sung-woo.kim>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Sungwoo Kim and committed by
Luiz Augusto von Dentz
10f9f426 4d7b41c0

+4 -5
+1 -2
net/bluetooth/hci_core.c
··· 2768 2768 2769 2769 hci_unregister_suspend_notifier(hdev); 2770 2770 2771 - msft_unregister(hdev); 2772 - 2773 2771 hci_dev_do_close(hdev); 2774 2772 2775 2773 if (!test_bit(HCI_INIT, &hdev->flags) && ··· 2821 2823 hci_discovery_filter_clear(hdev); 2822 2824 hci_blocked_keys_clear(hdev); 2823 2825 hci_codec_list_clear(&hdev->local_codecs); 2826 + msft_release(hdev); 2824 2827 hci_dev_unlock(hdev); 2825 2828 2826 2829 ida_destroy(&hdev->unset_handle_ida);
+1 -1
net/bluetooth/msft.c
··· 769 769 mutex_init(&msft->filter_lock); 770 770 } 771 771 772 - void msft_unregister(struct hci_dev *hdev) 772 + void msft_release(struct hci_dev *hdev) 773 773 { 774 774 struct msft_data *msft = hdev->msft_data; 775 775
+2 -2
net/bluetooth/msft.h
··· 14 14 15 15 bool msft_monitor_supported(struct hci_dev *hdev); 16 16 void msft_register(struct hci_dev *hdev); 17 - void msft_unregister(struct hci_dev *hdev); 17 + void msft_release(struct hci_dev *hdev); 18 18 void msft_do_open(struct hci_dev *hdev); 19 19 void msft_do_close(struct hci_dev *hdev); 20 20 void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb); ··· 35 35 } 36 36 37 37 static inline void msft_register(struct hci_dev *hdev) {} 38 - static inline void msft_unregister(struct hci_dev *hdev) {} 38 + static inline void msft_release(struct hci_dev *hdev) {} 39 39 static inline void msft_do_open(struct hci_dev *hdev) {} 40 40 static inline void msft_do_close(struct hci_dev *hdev) {} 41 41 static inline void msft_vendor_evt(struct hci_dev *hdev, void *data,