All of lore.kernel.org
 help / color / mirror / Atom feed
* [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove
@ 2024-09-01  8:24 syzbot
  2024-11-28  8:52 ` syzbot
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: syzbot @ 2024-09-01  8:24 UTC (permalink / raw)
  To: johan.hedberg, linux-bluetooth, linux-kernel, luiz.dentz, marcel,
	netdev, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    fe1910f9337b tcp_bpf: fix return value of tcp_bpf_sendmsg()
git tree:       net
console output: https://syzkaller.appspot.com/x/log.txt?x=171d6f7b980000
kernel config:  https://syzkaller.appspot.com/x/.config?x=996585887acdadb3
dashboard link: https://syzkaller.appspot.com/bug?extid=cc0cc52e7f43dc9e6df1
compiler:       Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/cb37d16e2860/disk-fe1910f9.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/315198aa296e/vmlinux-fe1910f9.xz
kernel image: https://storage.googleapis.com/syzbot-assets/b3e6fb9fa8a4/bzImage-fe1910f9.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+cc0cc52e7f43dc9e6df1@syzkaller.appspotmail.com

list_del corruption, ffff88802943da00->next is LIST_POISON1 (dead000000000100)
------------[ cut here ]------------
kernel BUG at lib/list_debug.c:58!
Oops: invalid opcode: 0000 [#1] PREEMPT SMP KASAN PTI
CPU: 1 UID: 0 PID: 7763 Comm: syz.0.694 Not tainted 6.11.0-rc5-syzkaller-00151-gfe1910f9337b #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/06/2024
RIP: 0010:__list_del_entry_valid_or_report+0xf4/0x140 lib/list_debug.c:56
Code: e8 71 64 fc 06 90 0f 0b 48 c7 c7 c0 90 60 8c 4c 89 fe e8 5f 64 fc 06 90 0f 0b 48 c7 c7 20 91 60 8c 4c 89 fe e8 4d 64 fc 06 90 <0f> 0b 48 c7 c7 80 91 60 8c 4c 89 fe e8 3b 64 fc 06 90 0f 0b 48 c7
RSP: 0018:ffffc9000492fb58 EFLAGS: 00010246
RAX: 000000000000004e RBX: dead000000000122 RCX: 5f038e50b22bff00
RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
RBP: dffffc0000000000 R08: ffffffff8174013c R09: 1ffff92000925f0c
R10: dffffc0000000000 R11: fffff52000925f0d R12: dffffc0000000000
R13: dffffc0000000000 R14: dead000000000100 R15: ffff88802943da00
FS:  00007fb7679de6c0(0000) GS:ffff8880b8900000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007ffc967a2fc0 CR3: 00000000437dc000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
 <TASK>
 __list_del_entry_valid include/linux/list.h:124 [inline]
 __list_del_entry include/linux/list.h:215 [inline]
 list_del include/linux/list.h:229 [inline]
 mgmt_pending_remove+0x26/0x1a0 net/bluetooth/mgmt_util.c:314
 mgmt_pending_foreach+0xd1/0x130 net/bluetooth/mgmt_util.c:259
 mgmt_index_removed+0xe6/0x340 net/bluetooth/mgmt.c:9395
 hci_sock_bind+0xcce/0x1150 net/bluetooth/hci_sock.c:1307
 __sys_bind_socket net/socket.c:1833 [inline]
 __sys_bind+0x23d/0x2f0 net/socket.c:1857
 __do_sys_bind net/socket.c:1865 [inline]
 __se_sys_bind net/socket.c:1863 [inline]
 __x64_sys_bind+0x7a/0x90 net/socket.c:1863
 do_syscall_x64 arch/x86/entry/common.c:52 [inline]
 do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7fb767f79eb9
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007fb7679de038 EFLAGS: 00000246 ORIG_RAX: 0000000000000031
RAX: ffffffffffffffda RBX: 00007fb768116058 RCX: 00007fb767f79eb9
RDX: 0000000000000006 RSI: 0000000020000040 RDI: 0000000000000004
RBP: 00007fb767fe793e R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 0000000000000001 R14: 00007fb768116058 R15: 00007fffd1ff2828
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:__list_del_entry_valid_or_report+0xf4/0x140 lib/list_debug.c:56
Code: e8 71 64 fc 06 90 0f 0b 48 c7 c7 c0 90 60 8c 4c 89 fe e8 5f 64 fc 06 90 0f 0b 48 c7 c7 20 91 60 8c 4c 89 fe e8 4d 64 fc 06 90 <0f> 0b 48 c7 c7 80 91 60 8c 4c 89 fe e8 3b 64 fc 06 90 0f 0b 48 c7
RSP: 0018:ffffc9000492fb58 EFLAGS: 00010246
RAX: 000000000000004e RBX: dead000000000122 RCX: 5f038e50b22bff00
RDX: 0000000000000000 RSI: 0000000080000000 RDI: 0000000000000000
RBP: dffffc0000000000 R08: ffffffff8174013c R09: 1ffff92000925f0c
R10: dffffc0000000000 R11: fffff52000925f0d R12: dffffc0000000000
R13: dffffc0000000000 R14: dead000000000100 R15: ffff88802943da00
FS:  00007fb7679de6c0(0000) GS:ffff8880b8900000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f773e8e8178 CR3: 00000000437dc000 CR4: 00000000003506f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove
  2024-09-01  8:24 [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove syzbot
@ 2024-11-28  8:52 ` syzbot
  2024-11-28 11:11   ` Hillf Danton
  2025-05-23  8:22 ` [syzbot] #syz test https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94305e83eccb3120c921cd3a015cd74731140bac syzbot
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: syzbot @ 2024-11-28  8:52 UTC (permalink / raw)
  To: johan.hedberg, linux-bluetooth, linux-kernel, luiz.dentz, marcel,
	netdev, syzkaller-bugs

syzbot has found a reproducer for the following issue on:

HEAD commit:    5dfd7d940094 Merge branch 'bnxt_en-bug-fixes'
git tree:       net
console output: https://syzkaller.appspot.com/x/log.txt?x=15a68f78580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=83e9a7f9e94ea674
dashboard link: https://syzkaller.appspot.com/bug?extid=cc0cc52e7f43dc9e6df1
compiler:       Debian clang version 15.0.6, GNU ld (GNU Binutils for Debian) 2.40
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=144ef530580000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=10c5ef5f980000

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/f4aa5ee37bd1/disk-5dfd7d94.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/d403277896b8/vmlinux-5dfd7d94.xz
kernel image: https://storage.googleapis.com/syzbot-assets/8ac17fc5f4ae/bzImage-5dfd7d94.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+cc0cc52e7f43dc9e6df1@syzkaller.appspotmail.com

==================================================================
BUG: KASAN: slab-use-after-free in __list_del_entry_valid_or_report+0x2f/0x140 lib/list_debug.c:49
Read of size 8 at addr ffff8881436c1888 by task kworker/u9:2/5853

CPU: 1 UID: 0 PID: 5853 Comm: kworker/u9:2 Not tainted 6.12.0-syzkaller-05517-g5dfd7d940094 #0
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024
Workqueue: hci0 hci_cmd_sync_work
Call Trace:
 <TASK>
 __dump_stack lib/dump_stack.c:94 [inline]
 dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:377 [inline]
 print_report+0x169/0x550 mm/kasan/report.c:488
 kasan_report+0x143/0x180 mm/kasan/report.c:601
 __list_del_entry_valid_or_report+0x2f/0x140 lib/list_debug.c:49
 __list_del_entry_valid include/linux/list.h:124 [inline]
 __list_del_entry include/linux/list.h:215 [inline]
 list_del include/linux/list.h:229 [inline]
 mgmt_pending_remove+0x26/0x1a0 net/bluetooth/mgmt_util.c:314
 mgmt_remove_adv_monitor_complete+0x2bf/0x550 net/bluetooth/mgmt.c:5522
 hci_cmd_sync_work+0x280/0x400 net/bluetooth/hci_sync.c:334
 process_one_work kernel/workqueue.c:3229 [inline]
 process_scheduled_works+0xa63/0x1850 kernel/workqueue.c:3310
 worker_thread+0x870/0xd30 kernel/workqueue.c:3391
 kthread+0x2f0/0x390 kernel/kthread.c:389
 ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:147
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
 </TASK>

Allocated by task 6082:
 kasan_save_stack mm/kasan/common.c:47 [inline]
 kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
 poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
 __kasan_kmalloc+0x98/0xb0 mm/kasan/common.c:394
 kasan_kmalloc include/linux/kasan.h:257 [inline]
 __kmalloc_cache_noprof+0x19c/0x2c0 mm/slub.c:4295
 kmalloc_noprof include/linux/slab.h:879 [inline]
 kzalloc_noprof include/linux/slab.h:1015 [inline]
 mgmt_pending_new+0x65/0x250 net/bluetooth/mgmt_util.c:269
 mgmt_pending_add+0x36/0x120 net/bluetooth/mgmt_util.c:296
 remove_adv_monitor+0x102/0x1b0 net/bluetooth/mgmt.c:5557
 hci_mgmt_cmd+0xc47/0x11d0 net/bluetooth/hci_sock.c:1712
 hci_sock_sendmsg+0x7b8/0x11c0 net/bluetooth/hci_sock.c:1832
 sock_sendmsg_nosec net/socket.c:711 [inline]
 __sock_sendmsg+0x221/0x270 net/socket.c:726
 sock_write_iter+0x2d7/0x3f0 net/socket.c:1147
 new_sync_write fs/read_write.c:586 [inline]
 vfs_write+0xaeb/0xd30 fs/read_write.c:679
 ksys_write+0x18f/0x2b0 fs/read_write.c:731
 do_syscall_x64 arch/x86/entry/common.c:52 [inline]
 do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Freed by task 6085:
 kasan_save_stack mm/kasan/common.c:47 [inline]
 kasan_save_track+0x3f/0x80 mm/kasan/common.c:68
 kasan_save_free_info+0x40/0x50 mm/kasan/generic.c:579
 poison_slab_object mm/kasan/common.c:247 [inline]
 __kasan_slab_free+0x59/0x70 mm/kasan/common.c:264
 kasan_slab_free include/linux/kasan.h:230 [inline]
 slab_free_hook mm/slub.c:2342 [inline]
 slab_free mm/slub.c:4579 [inline]
 kfree+0x1a0/0x440 mm/slub.c:4727
 mgmt_pending_foreach+0xd1/0x130 net/bluetooth/mgmt_util.c:259
 mgmt_index_removed+0x133/0x390 net/bluetooth/mgmt.c:9467
 hci_sock_bind+0xcce/0x1150 net/bluetooth/hci_sock.c:1307
 __sys_bind_socket net/socket.c:1827 [inline]
 __sys_bind+0x1e4/0x290 net/socket.c:1858
 __do_sys_bind net/socket.c:1863 [inline]
 __se_sys_bind net/socket.c:1861 [inline]
 __x64_sys_bind+0x7a/0x90 net/socket.c:1861
 do_syscall_x64 arch/x86/entry/common.c:52 [inline]
 do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

The buggy address belongs to the object at ffff8881436c1880
 which belongs to the cache kmalloc-96 of size 96
The buggy address is located 8 bytes inside of
 freed 96-byte region [ffff8881436c1880, ffff8881436c18e0)

The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0x1436c1
flags: 0x57ff00000000000(node=1|zone=2|lastcpupid=0x7ff)
page_type: f5(slab)
raw: 057ff00000000000 ffff88801b041280 dead000000000100 dead000000000122
raw: 0000000000000000 0000000080200020 00000001f5000000 0000000000000000
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x52cc0(GFP_KERNEL|__GFP_NOWARN|__GFP_NORETRY|__GFP_COMP), pid 1, tgid 1 (swapper/0), ts 3012747150, free_ts 0
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0x1f3/0x230 mm/page_alloc.c:1556
 prep_new_page mm/page_alloc.c:1564 [inline]
 get_page_from_freelist+0x3649/0x3790 mm/page_alloc.c:3474
 __alloc_pages_noprof+0x292/0x710 mm/page_alloc.c:4751
 alloc_pages_mpol_noprof+0x3e8/0x680 mm/mempolicy.c:2265
 alloc_slab_page+0x6a/0x140 mm/slub.c:2412
 allocate_slab+0x5a/0x2f0 mm/slub.c:2578
 new_slab mm/slub.c:2631 [inline]
 ___slab_alloc+0xcd1/0x14b0 mm/slub.c:3818
 __slab_alloc+0x58/0xa0 mm/slub.c:3908
 __slab_alloc_node mm/slub.c:3961 [inline]
 slab_alloc_node mm/slub.c:4122 [inline]
 __kmalloc_cache_noprof+0x1d5/0x2c0 mm/slub.c:4290
 kmalloc_noprof include/linux/slab.h:879 [inline]
 kzalloc_noprof include/linux/slab.h:1015 [inline]
 acpi_ut_evaluate_object+0x108/0x4a0 drivers/acpi/acpica/uteval.c:50
 acpi_ut_execute_HID+0xbf/0x3f0 drivers/acpi/acpica/utids.c:45
 acpi_get_object_info+0x328/0x1220 drivers/acpi/acpica/nsxfname.c:288
 acpi_set_pnp_ids drivers/acpi/scan.c:1410 [inline]
 acpi_init_device_object+0xbeb/0x31a0 drivers/acpi/scan.c:1829
 acpi_add_single_object+0x106/0x1e00 drivers/acpi/scan.c:1880
 acpi_bus_check_add+0x32b/0x980 drivers/acpi/scan.c:2181
 acpi_ns_walk_namespace+0x294/0x4f0
page_owner free stack trace missing

Memory state around the buggy address:
 ffff8881436c1780: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
 ffff8881436c1800: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
>ffff8881436c1880: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
                      ^
 ffff8881436c1900: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
 ffff8881436c1980: fa fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc
==================================================================


---
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove
  2024-11-28  8:52 ` syzbot
@ 2024-11-28 11:11   ` Hillf Danton
  0 siblings, 0 replies; 8+ messages in thread
From: Hillf Danton @ 2024-11-28 11:11 UTC (permalink / raw)
  To: syzbot; +Cc: linux-kernel, syzkaller-bugs

On Thu, 28 Nov 2024 00:52:26 -0800
> syzbot has found a reproducer for the following issue on:
> 
> HEAD commit:    5dfd7d940094 Merge branch 'bnxt_en-bug-fixes'
> git tree:       net
> C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=10c5ef5f980000

#stz test

--- x/net/bluetooth/hci_sync.c
+++ y/net/bluetooth/hci_sync.c
@@ -308,6 +308,7 @@ static void hci_cmd_sync_work(struct wor
 
 	bt_dev_dbg(hdev, "");
 
+	hci_req_sync_lock(hdev);
 	/* Dequeue all entries and run them */
 	while (1) {
 		struct hci_cmd_sync_work_entry *entry;
@@ -328,15 +329,14 @@ static void hci_cmd_sync_work(struct wor
 		if (entry->func) {
 			int err;
 
-			hci_req_sync_lock(hdev);
 			err = entry->func(hdev, entry->data);
 			if (entry->destroy)
 				entry->destroy(hdev, entry->data, err);
-			hci_req_sync_unlock(hdev);
 		}
 
 		kfree(entry);
 	}
+	hci_req_sync_unlock(hdev);
 }
 
 static void hci_cmd_sync_cancel_work(struct work_struct *work)
@@ -5192,6 +5192,15 @@ int hci_dev_close_sync(struct hci_dev *h
 			cancel_delayed_work_sync(&adv_instance->rpa_expired_cb);
 	}
 
+	do {
+		struct hci_cmd_sync_work_entry *entry, *tmp;
+
+		mutex_lock(&hdev->cmd_sync_work_lock);
+		list_for_each_entry_safe(entry, tmp, &hdev->cmd_sync_work_list, list)
+			_hci_cmd_sync_cancel_entry(hdev, entry, -ECANCELED);
+		mutex_unlock(&hdev->cmd_sync_work_lock);
+	} while (0);
+
 	/* Avoid potential lockdep warnings from the *_flush() calls by
 	 * ensuring the workqueue is empty up front.
 	 */
--

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] #syz test https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94305e83eccb3120c921cd3a015cd74731140bac
  2024-09-01  8:24 [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove syzbot
  2024-11-28  8:52 ` syzbot
@ 2025-05-23  8:22 ` syzbot
  2025-05-28 20:33 ` [syzbot] Re: [PATCH v1] Bluetooth: MGMT: Use RCU-protected in mgmt_pending list syzbot
  2025-06-02 18:02 ` [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock syzbot
  3 siblings, 0 replies; 8+ messages in thread
From: syzbot @ 2025-05-23  8:22 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: #syz test https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94305e83eccb3120c921cd3a015cd74731140bac
Author: dmantipov@yandex.ru

#syz test https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94305e83eccb3120c921cd3a015cd74731140bac

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] Re: [PATCH v1] Bluetooth: MGMT: Use RCU-protected in mgmt_pending list
  2024-09-01  8:24 [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove syzbot
  2024-11-28  8:52 ` syzbot
  2025-05-23  8:22 ` [syzbot] #syz test https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94305e83eccb3120c921cd3a015cd74731140bac syzbot
@ 2025-05-28 20:33 ` syzbot
  2025-06-02 18:02 ` [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock syzbot
  3 siblings, 0 replies; 8+ messages in thread
From: syzbot @ 2025-05-28 20:33 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: Re: [PATCH v1] Bluetooth: MGMT: Use RCU-protected in mgmt_pending list
Author: luiz.dentz@gmail.com

#syz test

On Wed, May 28, 2025 at 3:05 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> #syz test
>
> On Wed, May 28, 2025 at 3:03 PM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> >
> > #syz test
> >
> > On Wed, May 28, 2025 at 2:44 PM Luiz Augusto von Dentz
> > <luiz.dentz@gmail.com> wrote:
> > >
> > > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > >
> > > This uses RCU procedures to protect from concurrent access of
> > > mgmt_pending list which can cause crashes like:
> > >
> > > ==================================================================
> > > BUG: KASAN: slab-use-after-free in mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> > > Read of size 8 at addr ffff888048891a18 by task kworker/u5:8/5333
> > >
> > > CPU: 0 UID: 0 PID: 5333 Comm: kworker/u5:8 Not tainted 6.15.0-rc5-syzkaller-00197-gea34704d6ad7 #0 PREEMPT(full)
> > > Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> > > Workqueue: hci0 hci_cmd_sync_work
> > > Call Trace:
> > >  <TASK>
> > >  dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
> > >  print_address_description mm/kasan/report.c:408 [inline]
> > >  print_report+0xb4/0x290 mm/kasan/report.c:521
> > >  kasan_report+0x118/0x150 mm/kasan/report.c:634
> > >  mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> > >  hci_cmd_sync_work+0x25e/0x3a0 net/bluetooth/hci_sync.c:334
> > >  process_one_work kernel/workqueue.c:3238 [inline]
> > >  process_scheduled_works+0xadb/0x17a0 kernel/workqueue.c:3319
> > >  worker_thread+0x8a0/0xda0 kernel/workqueue.c:3400
> > >  kthread+0x70e/0x8a0 kernel/kthread.c:464
> > >  ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:153
> > >  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> > >  </TASK>
> > >
> > > Allocated by task 5702:
> > >  kasan_save_stack mm/kasan/common.c:47 [inline]
> > >  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
> > >  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
> > >  __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:394
> > >  kasan_kmalloc include/linux/kasan.h:260 [inline]
> > >  __kmalloc_cache_noprof+0x230/0x3d0 mm/slub.c:4358
> > >  kmalloc_noprof include/linux/slab.h:905 [inline]
> > >  kzalloc_noprof include/linux/slab.h:1039 [inline]
> > >  mgmt_pending_new+0x65/0x240 net/bluetooth/mgmt_util.c:252
> > >  mgmt_pending_add+0x34/0x120 net/bluetooth/mgmt_util.c:279
> > >  remove_adv_monitor+0x103/0x1b0 net/bluetooth/mgmt.c:5453
> > >  hci_mgmt_cmd+0x9c6/0xef0 net/bluetooth/hci_sock.c:1712
> > >  hci_sock_sendmsg+0x6ca/0xee0 net/bluetooth/hci_sock.c:1832
> > >  sock_sendmsg_nosec net/socket.c:712 [inline]
> > >  __sock_sendmsg+0x219/0x270 net/socket.c:727
> > >  sock_write_iter+0x258/0x330 net/socket.c:1131
> > >  new_sync_write fs/read_write.c:591 [inline]
> > >  vfs_write+0x548/0xa90 fs/read_write.c:684
> > >  ksys_write+0x145/0x250 fs/read_write.c:736
> > >  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> > >  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
> > >  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> > >
> > > Freed by task 5700:
> > >  kasan_save_stack mm/kasan/common.c:47 [inline]
> > >  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
> > >  kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
> > >  poison_slab_object mm/kasan/common.c:247 [inline]
> > >  __kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
> > >  kasan_slab_free include/linux/kasan.h:233 [inline]
> > >  slab_free_hook mm/slub.c:2380 [inline]
> > >  slab_free mm/slub.c:4642 [inline]
> > >  kfree+0x193/0x440 mm/slub.c:4841
> > >  mgmt_pending_foreach+0xc9/0x120 net/bluetooth/mgmt_util.c:242
> > >  mgmt_index_removed+0x10d/0x2f0 net/bluetooth/mgmt.c:9362
> > >  hci_sock_bind+0xbe9/0x1000 net/bluetooth/hci_sock.c:1307
> > >  __sys_bind_socket net/socket.c:1810 [inline]
> > >  __sys_bind+0x2c3/0x3e0 net/socket.c:1841
> > >  __do_sys_bind net/socket.c:1846 [inline]
> > >  __se_sys_bind net/socket.c:1844 [inline]
> > >  __x64_sys_bind+0x7a/0x90 net/socket.c:1844
> > >  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> > >  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
> > >  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> > >
> > > Fixes: a380b6cff1a2 ("Bluetooth: Add generic mgmt helper API")
> > > Closes: https://syzkaller.appspot.com/bug?extid=feb0dc579bbe30a13190
> > > Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
> > > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > > ---
> > >  net/bluetooth/mgmt_util.c | 25 +++++++++++++++----------
> > >  1 file changed, 15 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c
> > > index 3713ff490c65..c2dc8ddf5f78 100644
> > > --- a/net/bluetooth/mgmt_util.c
> > > +++ b/net/bluetooth/mgmt_util.c
> > > @@ -219,13 +219,20 @@ struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
> > >  {
> > >         struct mgmt_pending_cmd *cmd;
> > >
> > > -       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
> > > +       rcu_read_lock();
> > > +
> > > +       list_for_each_entry_rcu(cmd, &hdev->mgmt_pending, list) {
> > >                 if (hci_sock_get_channel(cmd->sk) != channel)
> > >                         continue;
> > > -               if (cmd->opcode == opcode)
> > > +
> > > +               if (cmd->opcode == opcode) {
> > > +                       rcu_read_unlock();
> > >                         return cmd;
> > > +               }
> > >         }
> > >
> > > +       rcu_read_unlock();
> > > +
> > >         return NULL;
> > >  }
> > >
> > > @@ -233,14 +240,11 @@ void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> > >                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
> > >                           void *data)
> > >  {
> > > -       struct mgmt_pending_cmd *cmd, *tmp;
> > > -
> > > -       list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
> > > -               if (opcode > 0 && cmd->opcode != opcode)
> > > -                       continue;
> > > +       struct mgmt_pending_cmd *cmd;
> > >
> > > +       cmd = mgmt_pending_find(HCI_CHANNEL_CONTROL, opcode, hdev);
> > > +       if (cmd)
> > >                 cb(cmd, data);
> > > -       }
> > >  }
> > >
> > >  struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
> > > @@ -280,7 +284,7 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
> > >         if (!cmd)
> > >                 return NULL;
> > >
> > > -       list_add_tail(&cmd->list, &hdev->mgmt_pending);
> > > +       list_add_tail_rcu(&cmd->list, &hdev->mgmt_pending);
> > >
> > >         return cmd;
> > >  }
> > > @@ -294,7 +298,8 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
> > >
> > >  void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
> > >  {
> > > -       list_del(&cmd->list);
> > > +       list_del_rcu(&cmd->list);
> > > +       synchronize_rcu();
> > >         mgmt_pending_free(cmd);
> > >  }
> > >
> > > --
> > > 2.49.0
> > >
> >
> >
> > --
> > Luiz Augusto von Dentz
>
>
>
> --
> Luiz Augusto von Dentz



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock
  2025-05-14  4:27 [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in mgmt_remove_adv_monitor_complete (3) syzbot
@ 2025-06-02 18:00 ` syzbot
  0 siblings, 0 replies; 8+ messages in thread
From: syzbot @ 2025-06-02 18:00 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock
Author: luiz.dentz@gmail.com

#syz test

On Mon, Jun 2, 2025 at 1:46 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This uses a mutex to protect from concurrent access of mgmt_pending
> list which can cause crashes like:
>
> ==================================================================
> BUG: KASAN: slab-use-after-free in mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> Read of size 8 at addr ffff888048891a18 by task kworker/u5:8/5333
>
> CPU: 0 UID: 0 PID: 5333 Comm: kworker/u5:8 Not tainted 6.15.0-rc5-syzkaller-00197-gea34704d6ad7 #0 PREEMPT(full)
> Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> Workqueue: hci0 hci_cmd_sync_work
> Call Trace:
>  <TASK>
>  dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
>  print_address_description mm/kasan/report.c:408 [inline]
>  print_report+0xb4/0x290 mm/kasan/report.c:521
>  kasan_report+0x118/0x150 mm/kasan/report.c:634
>  mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
>  hci_cmd_sync_work+0x25e/0x3a0 net/bluetooth/hci_sync.c:334
>  process_one_work kernel/workqueue.c:3238 [inline]
>  process_scheduled_works+0xadb/0x17a0 kernel/workqueue.c:3319
>  worker_thread+0x8a0/0xda0 kernel/workqueue.c:3400
>  kthread+0x70e/0x8a0 kernel/kthread.c:464
>  ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:153
>  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
>  </TASK>
>
> Allocated by task 5702:
>  kasan_save_stack mm/kasan/common.c:47 [inline]
>  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
>  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
>  __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:394
>  kasan_kmalloc include/linux/kasan.h:260 [inline]
>  __kmalloc_cache_noprof+0x230/0x3d0 mm/slub.c:4358
>  kmalloc_noprof include/linux/slab.h:905 [inline]
>  kzalloc_noprof include/linux/slab.h:1039 [inline]
>  mgmt_pending_new+0x65/0x240 net/bluetooth/mgmt_util.c:252
>  mgmt_pending_add+0x34/0x120 net/bluetooth/mgmt_util.c:279
>  remove_adv_monitor+0x103/0x1b0 net/bluetooth/mgmt.c:5453
>  hci_mgmt_cmd+0x9c6/0xef0 net/bluetooth/hci_sock.c:1712
>  hci_sock_sendmsg+0x6ca/0xee0 net/bluetooth/hci_sock.c:1832
>  sock_sendmsg_nosec net/socket.c:712 [inline]
>  __sock_sendmsg+0x219/0x270 net/socket.c:727
>  sock_write_iter+0x258/0x330 net/socket.c:1131
>  new_sync_write fs/read_write.c:591 [inline]
>  vfs_write+0x548/0xa90 fs/read_write.c:684
>  ksys_write+0x145/0x250 fs/read_write.c:736
>  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
>  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Freed by task 5700:
>  kasan_save_stack mm/kasan/common.c:47 [inline]
>  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
>  kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
>  poison_slab_object mm/kasan/common.c:247 [inline]
>  __kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
>  kasan_slab_free include/linux/kasan.h:233 [inline]
>  slab_free_hook mm/slub.c:2380 [inline]
>  slab_free mm/slub.c:4642 [inline]
>  kfree+0x193/0x440 mm/slub.c:4841
>  mgmt_pending_foreach+0xc9/0x120 net/bluetooth/mgmt_util.c:242
>  mgmt_index_removed+0x10d/0x2f0 net/bluetooth/mgmt.c:9362
>  hci_sock_bind+0xbe9/0x1000 net/bluetooth/hci_sock.c:1307
>  __sys_bind_socket net/socket.c:1810 [inline]
>  __sys_bind+0x2c3/0x3e0 net/socket.c:1841
>  __do_sys_bind net/socket.c:1846 [inline]
>  __se_sys_bind net/socket.c:1844 [inline]
>  __x64_sys_bind+0x7a/0x90 net/socket.c:1844
>  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
>  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
>  entry_SYSCALL_64_after_hwframe+0x77/0x7f
>
> Fixes: a380b6cff1a2 ("Bluetooth: Add generic mgmt helper API")
> Closes: https://syzkaller.appspot.com/bug?extid=feb0dc579bbe30a13190
> Closes: https://syzkaller.appspot.com/bug?extid=0a7039d5d9986ff4ececi
> Closes: https://syzkaller.appspot.com/bug?extid=cc0cc52e7f43dc9e6df1
> Reported-by: syzbot+feb0dc579bbe30a13190@syzkaller.appspotmail.com
> Tested-by: syzbot+feb0dc579bbe30a13190@syzkaller.appspotmail.com
> Tested-by: syzbot+0a7039d5d9986ff4ecec@syzkaller.appspotmail.com
> Tested-by: syzbot+cc0cc52e7f43dc9e6df1@syzkaller.appspotmail.com
> Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  include/net/bluetooth/hci_core.h |   1 +
>  net/bluetooth/hci_core.c         |   1 +
>  net/bluetooth/mgmt.c             | 101 +++++++++++++++----------------
>  net/bluetooth/mgmt_util.c        |  32 ++++++++--
>  net/bluetooth/mgmt_util.h        |   4 +-
>  5 files changed, 80 insertions(+), 59 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 2b261e74e2c4..b9ff0e825071 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -546,6 +546,7 @@ struct hci_dev {
>         struct hci_conn_hash    conn_hash;
>
>         struct list_head        mesh_pending;
> +       struct mutex            mgmt_pending_lock;
>         struct list_head        mgmt_pending;
>         struct list_head        reject_list;
>         struct list_head        accept_list;
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 04845ff3ad57..f197f5497043 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -2487,6 +2487,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
>
>         mutex_init(&hdev->lock);
>         mutex_init(&hdev->req_lock);
> +       mutex_init(&hdev->mgmt_pending_lock);
>
>         ida_init(&hdev->unset_handle_ida);
>
> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> index 14a9462fced5..7d9ed7db377f 100644
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -1447,22 +1447,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
>
>         send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
>
> -       list_del(&cmd->list);
> -
>         if (match->sk == NULL) {
>                 match->sk = cmd->sk;
>                 sock_hold(match->sk);
>         }
> -
> -       mgmt_pending_free(cmd);
>  }
>
>  static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
>  {
>         u8 *status = data;
>
> -       mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
> -       mgmt_pending_remove(cmd);
> +       mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status);
>  }
>
>  static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> @@ -1476,8 +1471,6 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
>
>         if (cmd->cmd_complete) {
>                 cmd->cmd_complete(cmd, match->mgmt_status);
> -               mgmt_pending_remove(cmd);
> -
>                 return;
>         }
>
> @@ -1486,13 +1479,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
>
>  static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
>  {
> -       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
> +       return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
>                                  cmd->param, cmd->param_len);
>  }
>
>  static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
>  {
> -       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
> +       return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
>                                  cmd->param, sizeof(struct mgmt_addr_info));
>  }
>
> @@ -1532,7 +1525,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
>
>         if (err) {
>                 u8 mgmt_err = mgmt_status(err);
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
>                 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
>                 goto done;
>         }
> @@ -1707,7 +1700,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
>
>         if (err) {
>                 u8 mgmt_err = mgmt_status(err);
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
>                 goto done;
>         }
>
> @@ -1943,8 +1936,8 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
>                         new_settings(hdev, NULL);
>                 }
>
> -               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
> -                                    &mgmt_err);
> +               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true,
> +                                    cmd_status_rsp, &mgmt_err);
>                 return;
>         }
>
> @@ -1954,7 +1947,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
>                 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
>         }
>
> -       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
> +       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match);
>
>         if (changed)
>                 new_settings(hdev, match.sk);
> @@ -2074,12 +2067,12 @@ static void set_le_complete(struct hci_dev *hdev, void *data, int err)
>         bt_dev_dbg(hdev, "err %d", err);
>
>         if (status) {
> -               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
> -                                                       &status);
> +               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp,
> +                                    &status);
>                 return;
>         }
>
> -       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
> +       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match);
>
>         new_settings(hdev, match.sk);
>
> @@ -2138,7 +2131,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
>         struct sock *sk = cmd->sk;
>
>         if (status) {
> -               mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev,
> +               mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
>                                      cmd_status_rsp, &status);
>                 return;
>         }
> @@ -2638,7 +2631,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
>
>         bt_dev_dbg(hdev, "err %d", err);
>
> -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                           mgmt_status(err), hdev->dev_class, 3);
>
>         mgmt_pending_free(cmd);
> @@ -3427,7 +3420,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
>         bacpy(&rp.addr.bdaddr, &conn->dst);
>         rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
>
> -       err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
> +       err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE,
>                                 status, &rp, sizeof(rp));
>
>         /* So we don't get further callbacks for this connection */
> @@ -5196,7 +5189,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
>                 hci_update_passive_scan(hdev);
>         }
>
> -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                           mgmt_status(status), &rp, sizeof(rp));
>         mgmt_pending_remove(cmd);
>
> @@ -5411,7 +5404,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
>         if (!status)
>                 hci_update_passive_scan(hdev);
>
> -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                           mgmt_status(status), &rp, sizeof(rp));
>         mgmt_pending_remove(cmd);
>
> @@ -5792,7 +5785,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
>             cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
>                 return;
>
> -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
>                           cmd->param, 1);
>         mgmt_pending_remove(cmd);
>
> @@ -6013,7 +6006,7 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
>
>         bt_dev_dbg(hdev, "err %d", err);
>
> -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
>                           cmd->param, 1);
>         mgmt_pending_remove(cmd);
>
> @@ -6238,7 +6231,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
>         u8 status = mgmt_status(err);
>
>         if (status) {
> -               mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
> +               mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true,
>                                      cmd_status_rsp, &status);
>                 return;
>         }
> @@ -6248,7 +6241,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
>         else
>                 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
>
> -       mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
> +       mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp,
>                              &match);
>
>         new_settings(hdev, match.sk);
> @@ -6592,7 +6585,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
>                  */
>                 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
>
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
>         } else {
>                 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
>                 new_settings(hdev, cmd->sk);
> @@ -6729,7 +6722,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
>         if (err) {
>                 u8 mgmt_err = mgmt_status(err);
>
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
>                 goto done;
>         }
>
> @@ -7176,7 +7169,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
>                 rp.max_tx_power = HCI_TX_POWER_INVALID;
>         }
>
> -       mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
>                           &rp, sizeof(rp));
>
>         mgmt_pending_free(cmd);
> @@ -7336,7 +7329,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
>         }
>
>  complete:
> -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
> +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
>                           sizeof(rp));
>
>         mgmt_pending_free(cmd);
> @@ -8586,10 +8579,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
>         rp.instance = cp->instance;
>
>         if (err)
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                 mgmt_status(err));
>         else
> -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                   mgmt_status(err), &rp, sizeof(rp));
>
>         add_adv_complete(hdev, cmd->sk, cp->instance, err);
> @@ -8777,10 +8770,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
>
>                 hci_remove_adv_instance(hdev, cp->instance);
>
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                 mgmt_status(err));
>         } else {
> -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                   mgmt_status(err), &rp, sizeof(rp));
>         }
>
> @@ -8927,10 +8920,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
>         rp.instance = cp->instance;
>
>         if (err)
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                 mgmt_status(err));
>         else
> -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                   mgmt_status(err), &rp, sizeof(rp));
>
>         mgmt_pending_free(cmd);
> @@ -9089,10 +9082,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
>         rp.instance = cp->instance;
>
>         if (err)
> -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                 mgmt_status(err));
>         else
> -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
>                                   MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
>
>         mgmt_pending_free(cmd);
> @@ -9364,7 +9357,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
>         if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
>                 return;
>
> -       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
> +       mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
>
>         if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
>                 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
> @@ -9402,7 +9395,8 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
>                 hci_update_passive_scan(hdev);
>         }
>
> -       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
> +       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
> +                            &match);
>
>         new_settings(hdev, match.sk);
>
> @@ -9417,7 +9411,8 @@ void __mgmt_power_off(struct hci_dev *hdev)
>         struct cmd_lookup match = { NULL, hdev };
>         u8 zero_cod[] = { 0, 0, 0 };
>
> -       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
> +       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
> +                            &match);
>
>         /* If the power off is because of hdev unregistration let
>          * use the appropriate INVALID_INDEX status. Otherwise use
> @@ -9431,7 +9426,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
>         else
>                 match.mgmt_status = MGMT_STATUS_NOT_POWERED;
>
> -       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
> +       mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
>
>         if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
>                 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
> @@ -9672,7 +9667,6 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
>         device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
>
>         cmd->cmd_complete(cmd, 0);
> -       mgmt_pending_remove(cmd);
>  }
>
>  bool mgmt_powering_down(struct hci_dev *hdev)
> @@ -9728,8 +9722,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
>         struct mgmt_cp_disconnect *cp;
>         struct mgmt_pending_cmd *cmd;
>
> -       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
> -                            hdev);
> +       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true,
> +                            unpair_device_rsp, hdev);
>
>         cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
>         if (!cmd)
> @@ -9922,7 +9916,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
>
>         if (status) {
>                 u8 mgmt_err = mgmt_status(status);
> -               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
> +               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
>                                      cmd_status_rsp, &mgmt_err);
>                 return;
>         }
> @@ -9932,8 +9926,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
>         else
>                 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
>
> -       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
> -                            &match);
> +       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
> +                            settings_rsp, &match);
>
>         if (changed)
>                 new_settings(hdev, match.sk);
> @@ -9957,9 +9951,12 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
>  {
>         struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
>
> -       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
> -       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
> -       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
> +       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup,
> +                            &match);
> +       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup,
> +                            &match);
> +       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup,
> +                            &match);
>
>         if (!status) {
>                 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
> diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c
> index 3713ff490c65..a88a07da3947 100644
> --- a/net/bluetooth/mgmt_util.c
> +++ b/net/bluetooth/mgmt_util.c
> @@ -217,30 +217,47 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
>  struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
>                                            struct hci_dev *hdev)
>  {
> -       struct mgmt_pending_cmd *cmd;
> +       struct mgmt_pending_cmd *cmd, *tmp;
>
> -       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
> +       mutex_lock(&hdev->mgmt_pending_lock);
> +
> +       list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
>                 if (hci_sock_get_channel(cmd->sk) != channel)
>                         continue;
> -               if (cmd->opcode == opcode)
> +
> +               if (cmd->opcode == opcode) {
> +                       mutex_unlock(&hdev->mgmt_pending_lock);
>                         return cmd;
> +               }
>         }
>
> +       mutex_unlock(&hdev->mgmt_pending_lock);
> +
>         return NULL;
>  }
>
> -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
>                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
>                           void *data)
>  {
>         struct mgmt_pending_cmd *cmd, *tmp;
>
> +       mutex_lock(&hdev->mgmt_pending_lock);
> +
>         list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
>                 if (opcode > 0 && cmd->opcode != opcode)
>                         continue;
>
> +               if (remove)
> +                       list_del(&cmd->list);
> +
>                 cb(cmd, data);
> +
> +               if (remove)
> +                       mgmt_pending_free(cmd);
>         }
> +
> +       mutex_unlock(&hdev->mgmt_pending_lock);
>  }
>
>  struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
> @@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
>                 return NULL;
>
>         cmd->opcode = opcode;
> -       cmd->index = hdev->id;
> +       cmd->hdev = hdev;
>
>         cmd->param = kmemdup(data, len, GFP_KERNEL);
>         if (!cmd->param) {
> @@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
>         if (!cmd)
>                 return NULL;
>
> +       mutex_lock(&hdev->mgmt_pending_lock);
>         list_add_tail(&cmd->list, &hdev->mgmt_pending);
> +       mutex_unlock(&hdev->mgmt_pending_lock);
>
>         return cmd;
>  }
> @@ -294,7 +313,10 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
>
>  void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
>  {
> +       mutex_lock(&cmd->hdev->mgmt_pending_lock);
>         list_del(&cmd->list);
> +       mutex_unlock(&cmd->hdev->mgmt_pending_lock);
> +
>         mgmt_pending_free(cmd);
>  }
>
> diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h
> index f2ba994ab1d8..024e51dd6937 100644
> --- a/net/bluetooth/mgmt_util.h
> +++ b/net/bluetooth/mgmt_util.h
> @@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
>  struct mgmt_pending_cmd {
>         struct list_head list;
>         u16 opcode;
> -       int index;
> +       struct hci_dev *hdev;
>         void *param;
>         size_t param_len;
>         struct sock *sk;
> @@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
>
>  struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
>                                            struct hci_dev *hdev);
> -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
>                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
>                           void *data);
>  struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
> --
> 2.49.0
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock
  2025-05-25  7:44 [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in hci_sock_get_channel syzbot
@ 2025-06-02 18:01 ` syzbot
  0 siblings, 0 replies; 8+ messages in thread
From: syzbot @ 2025-06-02 18:01 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock
Author: luiz.dentz@gmail.com

#syz test

On Mon, Jun 2, 2025 at 2:00 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> #syz test
>
> On Mon, Jun 2, 2025 at 1:46 PM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> >
> > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> >
> > This uses a mutex to protect from concurrent access of mgmt_pending
> > list which can cause crashes like:
> >
> > ==================================================================
> > BUG: KASAN: slab-use-after-free in mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> > Read of size 8 at addr ffff888048891a18 by task kworker/u5:8/5333
> >
> > CPU: 0 UID: 0 PID: 5333 Comm: kworker/u5:8 Not tainted 6.15.0-rc5-syzkaller-00197-gea34704d6ad7 #0 PREEMPT(full)
> > Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> > Workqueue: hci0 hci_cmd_sync_work
> > Call Trace:
> >  <TASK>
> >  dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
> >  print_address_description mm/kasan/report.c:408 [inline]
> >  print_report+0xb4/0x290 mm/kasan/report.c:521
> >  kasan_report+0x118/0x150 mm/kasan/report.c:634
> >  mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> >  hci_cmd_sync_work+0x25e/0x3a0 net/bluetooth/hci_sync.c:334
> >  process_one_work kernel/workqueue.c:3238 [inline]
> >  process_scheduled_works+0xadb/0x17a0 kernel/workqueue.c:3319
> >  worker_thread+0x8a0/0xda0 kernel/workqueue.c:3400
> >  kthread+0x70e/0x8a0 kernel/kthread.c:464
> >  ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:153
> >  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> >  </TASK>
> >
> > Allocated by task 5702:
> >  kasan_save_stack mm/kasan/common.c:47 [inline]
> >  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
> >  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
> >  __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:394
> >  kasan_kmalloc include/linux/kasan.h:260 [inline]
> >  __kmalloc_cache_noprof+0x230/0x3d0 mm/slub.c:4358
> >  kmalloc_noprof include/linux/slab.h:905 [inline]
> >  kzalloc_noprof include/linux/slab.h:1039 [inline]
> >  mgmt_pending_new+0x65/0x240 net/bluetooth/mgmt_util.c:252
> >  mgmt_pending_add+0x34/0x120 net/bluetooth/mgmt_util.c:279
> >  remove_adv_monitor+0x103/0x1b0 net/bluetooth/mgmt.c:5453
> >  hci_mgmt_cmd+0x9c6/0xef0 net/bluetooth/hci_sock.c:1712
> >  hci_sock_sendmsg+0x6ca/0xee0 net/bluetooth/hci_sock.c:1832
> >  sock_sendmsg_nosec net/socket.c:712 [inline]
> >  __sock_sendmsg+0x219/0x270 net/socket.c:727
> >  sock_write_iter+0x258/0x330 net/socket.c:1131
> >  new_sync_write fs/read_write.c:591 [inline]
> >  vfs_write+0x548/0xa90 fs/read_write.c:684
> >  ksys_write+0x145/0x250 fs/read_write.c:736
> >  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> >  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
> >  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> >
> > Freed by task 5700:
> >  kasan_save_stack mm/kasan/common.c:47 [inline]
> >  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
> >  kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
> >  poison_slab_object mm/kasan/common.c:247 [inline]
> >  __kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
> >  kasan_slab_free include/linux/kasan.h:233 [inline]
> >  slab_free_hook mm/slub.c:2380 [inline]
> >  slab_free mm/slub.c:4642 [inline]
> >  kfree+0x193/0x440 mm/slub.c:4841
> >  mgmt_pending_foreach+0xc9/0x120 net/bluetooth/mgmt_util.c:242
> >  mgmt_index_removed+0x10d/0x2f0 net/bluetooth/mgmt.c:9362
> >  hci_sock_bind+0xbe9/0x1000 net/bluetooth/hci_sock.c:1307
> >  __sys_bind_socket net/socket.c:1810 [inline]
> >  __sys_bind+0x2c3/0x3e0 net/socket.c:1841
> >  __do_sys_bind net/socket.c:1846 [inline]
> >  __se_sys_bind net/socket.c:1844 [inline]
> >  __x64_sys_bind+0x7a/0x90 net/socket.c:1844
> >  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> >  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
> >  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> >
> > Fixes: a380b6cff1a2 ("Bluetooth: Add generic mgmt helper API")
> > Closes: https://syzkaller.appspot.com/bug?extid=feb0dc579bbe30a13190
> > Closes: https://syzkaller.appspot.com/bug?extid=0a7039d5d9986ff4ececi
> > Closes: https://syzkaller.appspot.com/bug?extid=cc0cc52e7f43dc9e6df1
> > Reported-by: syzbot+feb0dc579bbe30a13190@syzkaller.appspotmail.com
> > Tested-by: syzbot+feb0dc579bbe30a13190@syzkaller.appspotmail.com
> > Tested-by: syzbot+0a7039d5d9986ff4ecec@syzkaller.appspotmail.com
> > Tested-by: syzbot+cc0cc52e7f43dc9e6df1@syzkaller.appspotmail.com
> > Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
> > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > ---
> >  include/net/bluetooth/hci_core.h |   1 +
> >  net/bluetooth/hci_core.c         |   1 +
> >  net/bluetooth/mgmt.c             | 101 +++++++++++++++----------------
> >  net/bluetooth/mgmt_util.c        |  32 ++++++++--
> >  net/bluetooth/mgmt_util.h        |   4 +-
> >  5 files changed, 80 insertions(+), 59 deletions(-)
> >
> > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> > index 2b261e74e2c4..b9ff0e825071 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -546,6 +546,7 @@ struct hci_dev {
> >         struct hci_conn_hash    conn_hash;
> >
> >         struct list_head        mesh_pending;
> > +       struct mutex            mgmt_pending_lock;
> >         struct list_head        mgmt_pending;
> >         struct list_head        reject_list;
> >         struct list_head        accept_list;
> > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> > index 04845ff3ad57..f197f5497043 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -2487,6 +2487,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
> >
> >         mutex_init(&hdev->lock);
> >         mutex_init(&hdev->req_lock);
> > +       mutex_init(&hdev->mgmt_pending_lock);
> >
> >         ida_init(&hdev->unset_handle_ida);
> >
> > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> > index 14a9462fced5..7d9ed7db377f 100644
> > --- a/net/bluetooth/mgmt.c
> > +++ b/net/bluetooth/mgmt.c
> > @@ -1447,22 +1447,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
> >
> >         send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
> >
> > -       list_del(&cmd->list);
> > -
> >         if (match->sk == NULL) {
> >                 match->sk = cmd->sk;
> >                 sock_hold(match->sk);
> >         }
> > -
> > -       mgmt_pending_free(cmd);
> >  }
> >
> >  static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
> >  {
> >         u8 *status = data;
> >
> > -       mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
> > -       mgmt_pending_remove(cmd);
> > +       mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status);
> >  }
> >
> >  static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > @@ -1476,8 +1471,6 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> >
> >         if (cmd->cmd_complete) {
> >                 cmd->cmd_complete(cmd, match->mgmt_status);
> > -               mgmt_pending_remove(cmd);
> > -
> >                 return;
> >         }
> >
> > @@ -1486,13 +1479,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> >
> >  static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
> >  {
> > -       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
> > +       return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
> >                                  cmd->param, cmd->param_len);
> >  }
> >
> >  static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
> >  {
> > -       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
> > +       return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
> >                                  cmd->param, sizeof(struct mgmt_addr_info));
> >  }
> >
> > @@ -1532,7 +1525,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
> >
> >         if (err) {
> >                 u8 mgmt_err = mgmt_status(err);
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> >                 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
> >                 goto done;
> >         }
> > @@ -1707,7 +1700,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
> >
> >         if (err) {
> >                 u8 mgmt_err = mgmt_status(err);
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> >                 goto done;
> >         }
> >
> > @@ -1943,8 +1936,8 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
> >                         new_settings(hdev, NULL);
> >                 }
> >
> > -               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
> > -                                    &mgmt_err);
> > +               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true,
> > +                                    cmd_status_rsp, &mgmt_err);
> >                 return;
> >         }
> >
> > @@ -1954,7 +1947,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
> >                 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
> >         }
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
> > +       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match);
> >
> >         if (changed)
> >                 new_settings(hdev, match.sk);
> > @@ -2074,12 +2067,12 @@ static void set_le_complete(struct hci_dev *hdev, void *data, int err)
> >         bt_dev_dbg(hdev, "err %d", err);
> >
> >         if (status) {
> > -               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
> > -                                                       &status);
> > +               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp,
> > +                                    &status);
> >                 return;
> >         }
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
> > +       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match);
> >
> >         new_settings(hdev, match.sk);
> >
> > @@ -2138,7 +2131,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
> >         struct sock *sk = cmd->sk;
> >
> >         if (status) {
> > -               mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev,
> > +               mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
> >                                      cmd_status_rsp, &status);
> >                 return;
> >         }
> > @@ -2638,7 +2631,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
> >
> >         bt_dev_dbg(hdev, "err %d", err);
> >
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                           mgmt_status(err), hdev->dev_class, 3);
> >
> >         mgmt_pending_free(cmd);
> > @@ -3427,7 +3420,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
> >         bacpy(&rp.addr.bdaddr, &conn->dst);
> >         rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
> >
> > -       err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
> > +       err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE,
> >                                 status, &rp, sizeof(rp));
> >
> >         /* So we don't get further callbacks for this connection */
> > @@ -5196,7 +5189,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
> >                 hci_update_passive_scan(hdev);
> >         }
> >
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                           mgmt_status(status), &rp, sizeof(rp));
> >         mgmt_pending_remove(cmd);
> >
> > @@ -5411,7 +5404,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
> >         if (!status)
> >                 hci_update_passive_scan(hdev);
> >
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                           mgmt_status(status), &rp, sizeof(rp));
> >         mgmt_pending_remove(cmd);
> >
> > @@ -5792,7 +5785,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
> >             cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
> >                 return;
> >
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
> >                           cmd->param, 1);
> >         mgmt_pending_remove(cmd);
> >
> > @@ -6013,7 +6006,7 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
> >
> >         bt_dev_dbg(hdev, "err %d", err);
> >
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
> >                           cmd->param, 1);
> >         mgmt_pending_remove(cmd);
> >
> > @@ -6238,7 +6231,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
> >         u8 status = mgmt_status(err);
> >
> >         if (status) {
> > -               mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
> > +               mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true,
> >                                      cmd_status_rsp, &status);
> >                 return;
> >         }
> > @@ -6248,7 +6241,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
> >         else
> >                 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
> > +       mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp,
> >                              &match);
> >
> >         new_settings(hdev, match.sk);
> > @@ -6592,7 +6585,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
> >                  */
> >                 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
> >
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> >         } else {
> >                 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
> >                 new_settings(hdev, cmd->sk);
> > @@ -6729,7 +6722,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
> >         if (err) {
> >                 u8 mgmt_err = mgmt_status(err);
> >
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> >                 goto done;
> >         }
> >
> > @@ -7176,7 +7169,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
> >                 rp.max_tx_power = HCI_TX_POWER_INVALID;
> >         }
> >
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
> >                           &rp, sizeof(rp));
> >
> >         mgmt_pending_free(cmd);
> > @@ -7336,7 +7329,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
> >         }
> >
> >  complete:
> > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
> > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
> >                           sizeof(rp));
> >
> >         mgmt_pending_free(cmd);
> > @@ -8586,10 +8579,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
> >         rp.instance = cp->instance;
> >
> >         if (err)
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                 mgmt_status(err));
> >         else
> > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                   mgmt_status(err), &rp, sizeof(rp));
> >
> >         add_adv_complete(hdev, cmd->sk, cp->instance, err);
> > @@ -8777,10 +8770,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
> >
> >                 hci_remove_adv_instance(hdev, cp->instance);
> >
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                 mgmt_status(err));
> >         } else {
> > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                   mgmt_status(err), &rp, sizeof(rp));
> >         }
> >
> > @@ -8927,10 +8920,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
> >         rp.instance = cp->instance;
> >
> >         if (err)
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                 mgmt_status(err));
> >         else
> > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                   mgmt_status(err), &rp, sizeof(rp));
> >
> >         mgmt_pending_free(cmd);
> > @@ -9089,10 +9082,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
> >         rp.instance = cp->instance;
> >
> >         if (err)
> > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                 mgmt_status(err));
> >         else
> > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> >                                   MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
> >
> >         mgmt_pending_free(cmd);
> > @@ -9364,7 +9357,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
> >         if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
> >                 return;
> >
> > -       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
> > +       mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
> >
> >         if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
> >                 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
> > @@ -9402,7 +9395,8 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
> >                 hci_update_passive_scan(hdev);
> >         }
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
> > +       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
> > +                            &match);
> >
> >         new_settings(hdev, match.sk);
> >
> > @@ -9417,7 +9411,8 @@ void __mgmt_power_off(struct hci_dev *hdev)
> >         struct cmd_lookup match = { NULL, hdev };
> >         u8 zero_cod[] = { 0, 0, 0 };
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
> > +       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
> > +                            &match);
> >
> >         /* If the power off is because of hdev unregistration let
> >          * use the appropriate INVALID_INDEX status. Otherwise use
> > @@ -9431,7 +9426,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
> >         else
> >                 match.mgmt_status = MGMT_STATUS_NOT_POWERED;
> >
> > -       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
> > +       mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
> >
> >         if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
> >                 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
> > @@ -9672,7 +9667,6 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
> >         device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
> >
> >         cmd->cmd_complete(cmd, 0);
> > -       mgmt_pending_remove(cmd);
> >  }
> >
> >  bool mgmt_powering_down(struct hci_dev *hdev)
> > @@ -9728,8 +9722,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
> >         struct mgmt_cp_disconnect *cp;
> >         struct mgmt_pending_cmd *cmd;
> >
> > -       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
> > -                            hdev);
> > +       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true,
> > +                            unpair_device_rsp, hdev);
> >
> >         cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
> >         if (!cmd)
> > @@ -9922,7 +9916,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
> >
> >         if (status) {
> >                 u8 mgmt_err = mgmt_status(status);
> > -               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
> > +               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
> >                                      cmd_status_rsp, &mgmt_err);
> >                 return;
> >         }
> > @@ -9932,8 +9926,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
> >         else
> >                 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
> > -                            &match);
> > +       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
> > +                            settings_rsp, &match);
> >
> >         if (changed)
> >                 new_settings(hdev, match.sk);
> > @@ -9957,9 +9951,12 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
> >  {
> >         struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
> >
> > -       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
> > -       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
> > -       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
> > +       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup,
> > +                            &match);
> > +       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup,
> > +                            &match);
> > +       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup,
> > +                            &match);
> >
> >         if (!status) {
> >                 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
> > diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c
> > index 3713ff490c65..a88a07da3947 100644
> > --- a/net/bluetooth/mgmt_util.c
> > +++ b/net/bluetooth/mgmt_util.c
> > @@ -217,30 +217,47 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
> >  struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
> >                                            struct hci_dev *hdev)
> >  {
> > -       struct mgmt_pending_cmd *cmd;
> > +       struct mgmt_pending_cmd *cmd, *tmp;
> >
> > -       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
> > +       mutex_lock(&hdev->mgmt_pending_lock);
> > +
> > +       list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
> >                 if (hci_sock_get_channel(cmd->sk) != channel)
> >                         continue;
> > -               if (cmd->opcode == opcode)
> > +
> > +               if (cmd->opcode == opcode) {
> > +                       mutex_unlock(&hdev->mgmt_pending_lock);
> >                         return cmd;
> > +               }
> >         }
> >
> > +       mutex_unlock(&hdev->mgmt_pending_lock);
> > +
> >         return NULL;
> >  }
> >
> > -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> > +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
> >                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
> >                           void *data)
> >  {
> >         struct mgmt_pending_cmd *cmd, *tmp;
> >
> > +       mutex_lock(&hdev->mgmt_pending_lock);
> > +
> >         list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
> >                 if (opcode > 0 && cmd->opcode != opcode)
> >                         continue;
> >
> > +               if (remove)
> > +                       list_del(&cmd->list);
> > +
> >                 cb(cmd, data);
> > +
> > +               if (remove)
> > +                       mgmt_pending_free(cmd);
> >         }
> > +
> > +       mutex_unlock(&hdev->mgmt_pending_lock);
> >  }
> >
> >  struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
> > @@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
> >                 return NULL;
> >
> >         cmd->opcode = opcode;
> > -       cmd->index = hdev->id;
> > +       cmd->hdev = hdev;
> >
> >         cmd->param = kmemdup(data, len, GFP_KERNEL);
> >         if (!cmd->param) {
> > @@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
> >         if (!cmd)
> >                 return NULL;
> >
> > +       mutex_lock(&hdev->mgmt_pending_lock);
> >         list_add_tail(&cmd->list, &hdev->mgmt_pending);
> > +       mutex_unlock(&hdev->mgmt_pending_lock);
> >
> >         return cmd;
> >  }
> > @@ -294,7 +313,10 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
> >
> >  void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
> >  {
> > +       mutex_lock(&cmd->hdev->mgmt_pending_lock);
> >         list_del(&cmd->list);
> > +       mutex_unlock(&cmd->hdev->mgmt_pending_lock);
> > +
> >         mgmt_pending_free(cmd);
> >  }
> >
> > diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h
> > index f2ba994ab1d8..024e51dd6937 100644
> > --- a/net/bluetooth/mgmt_util.h
> > +++ b/net/bluetooth/mgmt_util.h
> > @@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
> >  struct mgmt_pending_cmd {
> >         struct list_head list;
> >         u16 opcode;
> > -       int index;
> > +       struct hci_dev *hdev;
> >         void *param;
> >         size_t param_len;
> >         struct sock *sk;
> > @@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
> >
> >  struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
> >                                            struct hci_dev *hdev);
> > -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> > +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
> >                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
> >                           void *data);
> >  struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
> > --
> > 2.49.0
> >
>
>
> --
> Luiz Augusto von Dentz



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock
  2024-09-01  8:24 [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove syzbot
                   ` (2 preceding siblings ...)
  2025-05-28 20:33 ` [syzbot] Re: [PATCH v1] Bluetooth: MGMT: Use RCU-protected in mgmt_pending list syzbot
@ 2025-06-02 18:02 ` syzbot
  3 siblings, 0 replies; 8+ messages in thread
From: syzbot @ 2025-06-02 18:02 UTC (permalink / raw)
  To: linux-kernel, syzkaller-bugs

For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.

***

Subject: Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock
Author: luiz.dentz@gmail.com

#syz test

On Mon, Jun 2, 2025 at 2:01 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> #syz test
>
> On Mon, Jun 2, 2025 at 2:00 PM Luiz Augusto von Dentz <luiz.dentz@gmail.com> wrote:
> >
> > #syz test
> >
> > On Mon, Jun 2, 2025 at 1:46 PM Luiz Augusto von Dentz
> > <luiz.dentz@gmail.com> wrote:
> > >
> > > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > >
> > > This uses a mutex to protect from concurrent access of mgmt_pending
> > > list which can cause crashes like:
> > >
> > > ==================================================================
> > > BUG: KASAN: slab-use-after-free in mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> > > Read of size 8 at addr ffff888048891a18 by task kworker/u5:8/5333
> > >
> > > CPU: 0 UID: 0 PID: 5333 Comm: kworker/u5:8 Not tainted 6.15.0-rc5-syzkaller-00197-gea34704d6ad7 #0 PREEMPT(full)
> > > Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2~bpo12+1 04/01/2014
> > > Workqueue: hci0 hci_cmd_sync_work
> > > Call Trace:
> > >  <TASK>
> > >  dump_stack_lvl+0x189/0x250 lib/dump_stack.c:120
> > >  print_address_description mm/kasan/report.c:408 [inline]
> > >  print_report+0xb4/0x290 mm/kasan/report.c:521
> > >  kasan_report+0x118/0x150 mm/kasan/report.c:634
> > >  mgmt_remove_adv_monitor_complete+0xe5/0x540 net/bluetooth/mgmt.c:5405
> > >  hci_cmd_sync_work+0x25e/0x3a0 net/bluetooth/hci_sync.c:334
> > >  process_one_work kernel/workqueue.c:3238 [inline]
> > >  process_scheduled_works+0xadb/0x17a0 kernel/workqueue.c:3319
> > >  worker_thread+0x8a0/0xda0 kernel/workqueue.c:3400
> > >  kthread+0x70e/0x8a0 kernel/kthread.c:464
> > >  ret_from_fork+0x4b/0x80 arch/x86/kernel/process.c:153
> > >  ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
> > >  </TASK>
> > >
> > > Allocated by task 5702:
> > >  kasan_save_stack mm/kasan/common.c:47 [inline]
> > >  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
> > >  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
> > >  __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:394
> > >  kasan_kmalloc include/linux/kasan.h:260 [inline]
> > >  __kmalloc_cache_noprof+0x230/0x3d0 mm/slub.c:4358
> > >  kmalloc_noprof include/linux/slab.h:905 [inline]
> > >  kzalloc_noprof include/linux/slab.h:1039 [inline]
> > >  mgmt_pending_new+0x65/0x240 net/bluetooth/mgmt_util.c:252
> > >  mgmt_pending_add+0x34/0x120 net/bluetooth/mgmt_util.c:279
> > >  remove_adv_monitor+0x103/0x1b0 net/bluetooth/mgmt.c:5453
> > >  hci_mgmt_cmd+0x9c6/0xef0 net/bluetooth/hci_sock.c:1712
> > >  hci_sock_sendmsg+0x6ca/0xee0 net/bluetooth/hci_sock.c:1832
> > >  sock_sendmsg_nosec net/socket.c:712 [inline]
> > >  __sock_sendmsg+0x219/0x270 net/socket.c:727
> > >  sock_write_iter+0x258/0x330 net/socket.c:1131
> > >  new_sync_write fs/read_write.c:591 [inline]
> > >  vfs_write+0x548/0xa90 fs/read_write.c:684
> > >  ksys_write+0x145/0x250 fs/read_write.c:736
> > >  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> > >  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
> > >  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> > >
> > > Freed by task 5700:
> > >  kasan_save_stack mm/kasan/common.c:47 [inline]
> > >  kasan_save_track+0x3e/0x80 mm/kasan/common.c:68
> > >  kasan_save_free_info+0x46/0x50 mm/kasan/generic.c:576
> > >  poison_slab_object mm/kasan/common.c:247 [inline]
> > >  __kasan_slab_free+0x62/0x70 mm/kasan/common.c:264
> > >  kasan_slab_free include/linux/kasan.h:233 [inline]
> > >  slab_free_hook mm/slub.c:2380 [inline]
> > >  slab_free mm/slub.c:4642 [inline]
> > >  kfree+0x193/0x440 mm/slub.c:4841
> > >  mgmt_pending_foreach+0xc9/0x120 net/bluetooth/mgmt_util.c:242
> > >  mgmt_index_removed+0x10d/0x2f0 net/bluetooth/mgmt.c:9362
> > >  hci_sock_bind+0xbe9/0x1000 net/bluetooth/hci_sock.c:1307
> > >  __sys_bind_socket net/socket.c:1810 [inline]
> > >  __sys_bind+0x2c3/0x3e0 net/socket.c:1841
> > >  __do_sys_bind net/socket.c:1846 [inline]
> > >  __se_sys_bind net/socket.c:1844 [inline]
> > >  __x64_sys_bind+0x7a/0x90 net/socket.c:1844
> > >  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
> > >  do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94
> > >  entry_SYSCALL_64_after_hwframe+0x77/0x7f
> > >
> > > Fixes: a380b6cff1a2 ("Bluetooth: Add generic mgmt helper API")
> > > Closes: https://syzkaller.appspot.com/bug?extid=feb0dc579bbe30a13190
> > > Closes: https://syzkaller.appspot.com/bug?extid=0a7039d5d9986ff4ececi
> > > Closes: https://syzkaller.appspot.com/bug?extid=cc0cc52e7f43dc9e6df1
> > > Reported-by: syzbot+feb0dc579bbe30a13190@syzkaller.appspotmail.com
> > > Tested-by: syzbot+feb0dc579bbe30a13190@syzkaller.appspotmail.com
> > > Tested-by: syzbot+0a7039d5d9986ff4ecec@syzkaller.appspotmail.com
> > > Tested-by: syzbot+cc0cc52e7f43dc9e6df1@syzkaller.appspotmail.com
> > > Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
> > > Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > > ---
> > >  include/net/bluetooth/hci_core.h |   1 +
> > >  net/bluetooth/hci_core.c         |   1 +
> > >  net/bluetooth/mgmt.c             | 101 +++++++++++++++----------------
> > >  net/bluetooth/mgmt_util.c        |  32 ++++++++--
> > >  net/bluetooth/mgmt_util.h        |   4 +-
> > >  5 files changed, 80 insertions(+), 59 deletions(-)
> > >
> > > diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> > > index 2b261e74e2c4..b9ff0e825071 100644
> > > --- a/include/net/bluetooth/hci_core.h
> > > +++ b/include/net/bluetooth/hci_core.h
> > > @@ -546,6 +546,7 @@ struct hci_dev {
> > >         struct hci_conn_hash    conn_hash;
> > >
> > >         struct list_head        mesh_pending;
> > > +       struct mutex            mgmt_pending_lock;
> > >         struct list_head        mgmt_pending;
> > >         struct list_head        reject_list;
> > >         struct list_head        accept_list;
> > > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> > > index 04845ff3ad57..f197f5497043 100644
> > > --- a/net/bluetooth/hci_core.c
> > > +++ b/net/bluetooth/hci_core.c
> > > @@ -2487,6 +2487,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
> > >
> > >         mutex_init(&hdev->lock);
> > >         mutex_init(&hdev->req_lock);
> > > +       mutex_init(&hdev->mgmt_pending_lock);
> > >
> > >         ida_init(&hdev->unset_handle_ida);
> > >
> > > diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
> > > index 14a9462fced5..7d9ed7db377f 100644
> > > --- a/net/bluetooth/mgmt.c
> > > +++ b/net/bluetooth/mgmt.c
> > > @@ -1447,22 +1447,17 @@ static void settings_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > >
> > >         send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
> > >
> > > -       list_del(&cmd->list);
> > > -
> > >         if (match->sk == NULL) {
> > >                 match->sk = cmd->sk;
> > >                 sock_hold(match->sk);
> > >         }
> > > -
> > > -       mgmt_pending_free(cmd);
> > >  }
> > >
> > >  static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > >  {
> > >         u8 *status = data;
> > >
> > > -       mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
> > > -       mgmt_pending_remove(cmd);
> > > +       mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status);
> > >  }
> > >
> > >  static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > > @@ -1476,8 +1471,6 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > >
> > >         if (cmd->cmd_complete) {
> > >                 cmd->cmd_complete(cmd, match->mgmt_status);
> > > -               mgmt_pending_remove(cmd);
> > > -
> > >                 return;
> > >         }
> > >
> > > @@ -1486,13 +1479,13 @@ static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > >
> > >  static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
> > >  {
> > > -       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
> > > +       return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
> > >                                  cmd->param, cmd->param_len);
> > >  }
> > >
> > >  static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status)
> > >  {
> > > -       return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status,
> > > +       return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status,
> > >                                  cmd->param, sizeof(struct mgmt_addr_info));
> > >  }
> > >
> > > @@ -1532,7 +1525,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
> > >
> > >         if (err) {
> > >                 u8 mgmt_err = mgmt_status(err);
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> > >                 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE);
> > >                 goto done;
> > >         }
> > > @@ -1707,7 +1700,7 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
> > >
> > >         if (err) {
> > >                 u8 mgmt_err = mgmt_status(err);
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> > >                 goto done;
> > >         }
> > >
> > > @@ -1943,8 +1936,8 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
> > >                         new_settings(hdev, NULL);
> > >                 }
> > >
> > > -               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
> > > -                                    &mgmt_err);
> > > +               mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true,
> > > +                                    cmd_status_rsp, &mgmt_err);
> > >                 return;
> > >         }
> > >
> > > @@ -1954,7 +1947,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
> > >                 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED);
> > >         }
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
> > > +       mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match);
> > >
> > >         if (changed)
> > >                 new_settings(hdev, match.sk);
> > > @@ -2074,12 +2067,12 @@ static void set_le_complete(struct hci_dev *hdev, void *data, int err)
> > >         bt_dev_dbg(hdev, "err %d", err);
> > >
> > >         if (status) {
> > > -               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
> > > -                                                       &status);
> > > +               mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp,
> > > +                                    &status);
> > >                 return;
> > >         }
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
> > > +       mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match);
> > >
> > >         new_settings(hdev, match.sk);
> > >
> > > @@ -2138,7 +2131,7 @@ static void set_mesh_complete(struct hci_dev *hdev, void *data, int err)
> > >         struct sock *sk = cmd->sk;
> > >
> > >         if (status) {
> > > -               mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev,
> > > +               mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true,
> > >                                      cmd_status_rsp, &status);
> > >                 return;
> > >         }
> > > @@ -2638,7 +2631,7 @@ static void mgmt_class_complete(struct hci_dev *hdev, void *data, int err)
> > >
> > >         bt_dev_dbg(hdev, "err %d", err);
> > >
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                           mgmt_status(err), hdev->dev_class, 3);
> > >
> > >         mgmt_pending_free(cmd);
> > > @@ -3427,7 +3420,7 @@ static int pairing_complete(struct mgmt_pending_cmd *cmd, u8 status)
> > >         bacpy(&rp.addr.bdaddr, &conn->dst);
> > >         rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
> > >
> > > -       err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE,
> > > +       err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE,
> > >                                 status, &rp, sizeof(rp));
> > >
> > >         /* So we don't get further callbacks for this connection */
> > > @@ -5196,7 +5189,7 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,
> > >                 hci_update_passive_scan(hdev);
> > >         }
> > >
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                           mgmt_status(status), &rp, sizeof(rp));
> > >         mgmt_pending_remove(cmd);
> > >
> > > @@ -5411,7 +5404,7 @@ static void mgmt_remove_adv_monitor_complete(struct hci_dev *hdev,
> > >         if (!status)
> > >                 hci_update_passive_scan(hdev);
> > >
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                           mgmt_status(status), &rp, sizeof(rp));
> > >         mgmt_pending_remove(cmd);
> > >
> > > @@ -5792,7 +5785,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
> > >             cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
> > >                 return;
> > >
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
> > >                           cmd->param, 1);
> > >         mgmt_pending_remove(cmd);
> > >
> > > @@ -6013,7 +6006,7 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
> > >
> > >         bt_dev_dbg(hdev, "err %d", err);
> > >
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err),
> > >                           cmd->param, 1);
> > >         mgmt_pending_remove(cmd);
> > >
> > > @@ -6238,7 +6231,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
> > >         u8 status = mgmt_status(err);
> > >
> > >         if (status) {
> > > -               mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
> > > +               mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true,
> > >                                      cmd_status_rsp, &status);
> > >                 return;
> > >         }
> > > @@ -6248,7 +6241,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
> > >         else
> > >                 hci_dev_clear_flag(hdev, HCI_ADVERTISING);
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
> > > +       mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp,
> > >                              &match);
> > >
> > >         new_settings(hdev, match.sk);
> > > @@ -6592,7 +6585,7 @@ static void set_bredr_complete(struct hci_dev *hdev, void *data, int err)
> > >                  */
> > >                 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED);
> > >
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> > >         } else {
> > >                 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
> > >                 new_settings(hdev, cmd->sk);
> > > @@ -6729,7 +6722,7 @@ static void set_secure_conn_complete(struct hci_dev *hdev, void *data, int err)
> > >         if (err) {
> > >                 u8 mgmt_err = mgmt_status(err);
> > >
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
> > >                 goto done;
> > >         }
> > >
> > > @@ -7176,7 +7169,7 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
> > >                 rp.max_tx_power = HCI_TX_POWER_INVALID;
> > >         }
> > >
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status,
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
> > >                           &rp, sizeof(rp));
> > >
> > >         mgmt_pending_free(cmd);
> > > @@ -7336,7 +7329,7 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
> > >         }
> > >
> > >  complete:
> > > -       mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp,
> > > +       mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
> > >                           sizeof(rp));
> > >
> > >         mgmt_pending_free(cmd);
> > > @@ -8586,10 +8579,10 @@ static void add_advertising_complete(struct hci_dev *hdev, void *data, int err)
> > >         rp.instance = cp->instance;
> > >
> > >         if (err)
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                 mgmt_status(err));
> > >         else
> > > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                   mgmt_status(err), &rp, sizeof(rp));
> > >
> > >         add_adv_complete(hdev, cmd->sk, cp->instance, err);
> > > @@ -8777,10 +8770,10 @@ static void add_ext_adv_params_complete(struct hci_dev *hdev, void *data,
> > >
> > >                 hci_remove_adv_instance(hdev, cp->instance);
> > >
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                 mgmt_status(err));
> > >         } else {
> > > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                   mgmt_status(err), &rp, sizeof(rp));
> > >         }
> > >
> > > @@ -8927,10 +8920,10 @@ static void add_ext_adv_data_complete(struct hci_dev *hdev, void *data, int err)
> > >         rp.instance = cp->instance;
> > >
> > >         if (err)
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                 mgmt_status(err));
> > >         else
> > > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                   mgmt_status(err), &rp, sizeof(rp));
> > >
> > >         mgmt_pending_free(cmd);
> > > @@ -9089,10 +9082,10 @@ static void remove_advertising_complete(struct hci_dev *hdev, void *data,
> > >         rp.instance = cp->instance;
> > >
> > >         if (err)
> > > -               mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                 mgmt_status(err));
> > >         else
> > > -               mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> > > +               mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode,
> > >                                   MGMT_STATUS_SUCCESS, &rp, sizeof(rp));
> > >
> > >         mgmt_pending_free(cmd);
> > > @@ -9364,7 +9357,7 @@ void mgmt_index_removed(struct hci_dev *hdev)
> > >         if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
> > >                 return;
> > >
> > > -       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
> > > +       mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
> > >
> > >         if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
> > >                 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0,
> > > @@ -9402,7 +9395,8 @@ void mgmt_power_on(struct hci_dev *hdev, int err)
> > >                 hci_update_passive_scan(hdev);
> > >         }
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
> > > +       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
> > > +                            &match);
> > >
> > >         new_settings(hdev, match.sk);
> > >
> > > @@ -9417,7 +9411,8 @@ void __mgmt_power_off(struct hci_dev *hdev)
> > >         struct cmd_lookup match = { NULL, hdev };
> > >         u8 zero_cod[] = { 0, 0, 0 };
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
> > > +       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp,
> > > +                            &match);
> > >
> > >         /* If the power off is because of hdev unregistration let
> > >          * use the appropriate INVALID_INDEX status. Otherwise use
> > > @@ -9431,7 +9426,7 @@ void __mgmt_power_off(struct hci_dev *hdev)
> > >         else
> > >                 match.mgmt_status = MGMT_STATUS_NOT_POWERED;
> > >
> > > -       mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match);
> > > +       mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match);
> > >
> > >         if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
> > >                 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
> > > @@ -9672,7 +9667,6 @@ static void unpair_device_rsp(struct mgmt_pending_cmd *cmd, void *data)
> > >         device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
> > >
> > >         cmd->cmd_complete(cmd, 0);
> > > -       mgmt_pending_remove(cmd);
> > >  }
> > >
> > >  bool mgmt_powering_down(struct hci_dev *hdev)
> > > @@ -9728,8 +9722,8 @@ void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
> > >         struct mgmt_cp_disconnect *cp;
> > >         struct mgmt_pending_cmd *cmd;
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
> > > -                            hdev);
> > > +       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true,
> > > +                            unpair_device_rsp, hdev);
> > >
> > >         cmd = pending_find(MGMT_OP_DISCONNECT, hdev);
> > >         if (!cmd)
> > > @@ -9922,7 +9916,7 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
> > >
> > >         if (status) {
> > >                 u8 mgmt_err = mgmt_status(status);
> > > -               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
> > > +               mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
> > >                                      cmd_status_rsp, &mgmt_err);
> > >                 return;
> > >         }
> > > @@ -9932,8 +9926,8 @@ void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
> > >         else
> > >                 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY);
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
> > > -                            &match);
> > > +       mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true,
> > > +                            settings_rsp, &match);
> > >
> > >         if (changed)
> > >                 new_settings(hdev, match.sk);
> > > @@ -9957,9 +9951,12 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
> > >  {
> > >         struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
> > >
> > > -       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
> > > -       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
> > > -       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
> > > +       mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup,
> > > +                            &match);
> > > +       mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup,
> > > +                            &match);
> > > +       mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup,
> > > +                            &match);
> > >
> > >         if (!status) {
> > >                 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
> > > diff --git a/net/bluetooth/mgmt_util.c b/net/bluetooth/mgmt_util.c
> > > index 3713ff490c65..a88a07da3947 100644
> > > --- a/net/bluetooth/mgmt_util.c
> > > +++ b/net/bluetooth/mgmt_util.c
> > > @@ -217,30 +217,47 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
> > >  struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
> > >                                            struct hci_dev *hdev)
> > >  {
> > > -       struct mgmt_pending_cmd *cmd;
> > > +       struct mgmt_pending_cmd *cmd, *tmp;
> > >
> > > -       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
> > > +       mutex_lock(&hdev->mgmt_pending_lock);
> > > +
> > > +       list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
> > >                 if (hci_sock_get_channel(cmd->sk) != channel)
> > >                         continue;
> > > -               if (cmd->opcode == opcode)
> > > +
> > > +               if (cmd->opcode == opcode) {
> > > +                       mutex_unlock(&hdev->mgmt_pending_lock);
> > >                         return cmd;
> > > +               }
> > >         }
> > >
> > > +       mutex_unlock(&hdev->mgmt_pending_lock);
> > > +
> > >         return NULL;
> > >  }
> > >
> > > -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> > > +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
> > >                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
> > >                           void *data)
> > >  {
> > >         struct mgmt_pending_cmd *cmd, *tmp;
> > >
> > > +       mutex_lock(&hdev->mgmt_pending_lock);
> > > +
> > >         list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
> > >                 if (opcode > 0 && cmd->opcode != opcode)
> > >                         continue;
> > >
> > > +               if (remove)
> > > +                       list_del(&cmd->list);
> > > +
> > >                 cb(cmd, data);
> > > +
> > > +               if (remove)
> > > +                       mgmt_pending_free(cmd);
> > >         }
> > > +
> > > +       mutex_unlock(&hdev->mgmt_pending_lock);
> > >  }
> > >
> > >  struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
> > > @@ -254,7 +271,7 @@ struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode,
> > >                 return NULL;
> > >
> > >         cmd->opcode = opcode;
> > > -       cmd->index = hdev->id;
> > > +       cmd->hdev = hdev;
> > >
> > >         cmd->param = kmemdup(data, len, GFP_KERNEL);
> > >         if (!cmd->param) {
> > > @@ -280,7 +297,9 @@ struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
> > >         if (!cmd)
> > >                 return NULL;
> > >
> > > +       mutex_lock(&hdev->mgmt_pending_lock);
> > >         list_add_tail(&cmd->list, &hdev->mgmt_pending);
> > > +       mutex_unlock(&hdev->mgmt_pending_lock);
> > >
> > >         return cmd;
> > >  }
> > > @@ -294,7 +313,10 @@ void mgmt_pending_free(struct mgmt_pending_cmd *cmd)
> > >
> > >  void mgmt_pending_remove(struct mgmt_pending_cmd *cmd)
> > >  {
> > > +       mutex_lock(&cmd->hdev->mgmt_pending_lock);
> > >         list_del(&cmd->list);
> > > +       mutex_unlock(&cmd->hdev->mgmt_pending_lock);
> > > +
> > >         mgmt_pending_free(cmd);
> > >  }
> > >
> > > diff --git a/net/bluetooth/mgmt_util.h b/net/bluetooth/mgmt_util.h
> > > index f2ba994ab1d8..024e51dd6937 100644
> > > --- a/net/bluetooth/mgmt_util.h
> > > +++ b/net/bluetooth/mgmt_util.h
> > > @@ -33,7 +33,7 @@ struct mgmt_mesh_tx {
> > >  struct mgmt_pending_cmd {
> > >         struct list_head list;
> > >         u16 opcode;
> > > -       int index;
> > > +       struct hci_dev *hdev;
> > >         void *param;
> > >         size_t param_len;
> > >         struct sock *sk;
> > > @@ -54,7 +54,7 @@ int mgmt_cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
> > >
> > >  struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode,
> > >                                            struct hci_dev *hdev);
> > > -void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
> > > +void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove,
> > >                           void (*cb)(struct mgmt_pending_cmd *cmd, void *data),
> > >                           void *data);
> > >  struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
> > > --
> > > 2.49.0
> > >
> >
> >
> > --
> > Luiz Augusto von Dentz
>
>
>
> --
> Luiz Augusto von Dentz



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-06-02 18:02 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-01  8:24 [syzbot] [bluetooth?] BUG: corrupted list in mgmt_pending_remove syzbot
2024-11-28  8:52 ` syzbot
2024-11-28 11:11   ` Hillf Danton
2025-05-23  8:22 ` [syzbot] #syz test https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 94305e83eccb3120c921cd3a015cd74731140bac syzbot
2025-05-28 20:33 ` [syzbot] Re: [PATCH v1] Bluetooth: MGMT: Use RCU-protected in mgmt_pending list syzbot
2025-06-02 18:02 ` [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock syzbot
  -- strict thread matches above, loose matches on Subject: below --
2025-05-14  4:27 [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in mgmt_remove_adv_monitor_complete (3) syzbot
2025-06-02 18:00 ` [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock syzbot
2025-05-25  7:44 [syzbot] [bluetooth?] KASAN: slab-use-after-free Read in hci_sock_get_channel syzbot
2025-06-02 18:01 ` [syzbot] Re: [PATCH v3] Bluetooth: MGMT: Protect mgmt_pending list with its own lock syzbot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.