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

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: hci_sync: fix double free in 'hci_discovery_filter_clear()'

Function 'hci_discovery_filter_clear()' frees 'uuids' array and then
sets it to NULL. There is a tiny chance of the following race:

'hci_cmd_sync_work()'

'update_passive_scan_sync()'

'hci_update_passive_scan_sync()'

'hci_discovery_filter_clear()'
kfree(uuids);

<-------------------------preempted-------------------------------->
'start_service_discovery()'

'hci_discovery_filter_clear()'
kfree(uuids); // DOUBLE FREE

<-------------------------preempted-------------------------------->

uuids = NULL;

To fix it let's add locking around 'kfree()' call and NULL pointer
assignment. Otherwise the following backtrace fires:

[ ] ------------[ cut here ]------------
[ ] kernel BUG at mm/slub.c:547!
[ ] Internal error: Oops - BUG: 00000000f2000800 [#1] PREEMPT SMP
[ ] CPU: 3 UID: 0 PID: 246 Comm: bluetoothd Tainted: G O 6.12.19-kernel #1
[ ] Tainted: [O]=OOT_MODULE
[ ] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ ] pc : __slab_free+0xf8/0x348
[ ] lr : __slab_free+0x48/0x348
...
[ ] Call trace:
[ ] __slab_free+0xf8/0x348
[ ] kfree+0x164/0x27c
[ ] start_service_discovery+0x1d0/0x2c0
[ ] hci_sock_sendmsg+0x518/0x924
[ ] __sock_sendmsg+0x54/0x60
[ ] sock_write_iter+0x98/0xf8
[ ] do_iter_readv_writev+0xe4/0x1c8
[ ] vfs_writev+0x128/0x2b0
[ ] do_writev+0xfc/0x118
[ ] __arm64_sys_writev+0x20/0x2c
[ ] invoke_syscall+0x68/0xf0
[ ] el0_svc_common.constprop.0+0x40/0xe0
[ ] do_el0_svc+0x1c/0x28
[ ] el0_svc+0x30/0xd0
[ ] el0t_64_sync_handler+0x100/0x12c
[ ] el0t_64_sync+0x194/0x198
[ ] Code: 8b0002e6 eb17031f 54fffbe1 d503201f (d4210000)
[ ] ---[ end trace 0000000000000000 ]---

Fixes: ad383c2c65a5 ("Bluetooth: hci_sync: Enable advertising when LL privacy is enabled")
Signed-off-by: Arseniy Krasnov <avkrasnov@salutedevices.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Arseniy Krasnov and committed by
Luiz Augusto von Dentz
2935e556 c20284f7

+6
+6
include/net/bluetooth/hci_core.h
··· 29 29 #include <linux/idr.h> 30 30 #include <linux/leds.h> 31 31 #include <linux/rculist.h> 32 + #include <linux/spinlock.h> 32 33 #include <linux/srcu.h> 33 34 34 35 #include <net/bluetooth/hci.h> ··· 95 94 u16 uuid_count; 96 95 u8 (*uuids)[16]; 97 96 unsigned long name_resolve_timeout; 97 + spinlock_t lock; 98 98 }; 99 99 100 100 #define SUSPEND_NOTIFIER_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ ··· 891 889 892 890 static inline void discovery_init(struct hci_dev *hdev) 893 891 { 892 + spin_lock_init(&hdev->discovery.lock); 894 893 hdev->discovery.state = DISCOVERY_STOPPED; 895 894 INIT_LIST_HEAD(&hdev->discovery.all); 896 895 INIT_LIST_HEAD(&hdev->discovery.unknown); ··· 906 903 hdev->discovery.report_invalid_rssi = true; 907 904 hdev->discovery.rssi = HCI_RSSI_INVALID; 908 905 hdev->discovery.uuid_count = 0; 906 + 907 + spin_lock(&hdev->discovery.lock); 909 908 kfree(hdev->discovery.uuids); 910 909 hdev->discovery.uuids = NULL; 910 + spin_unlock(&hdev->discovery.lock); 911 911 } 912 912 913 913 bool hci_discovery_active(struct hci_dev *hdev);