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

Bluetooth: MGMT: Protect mgmt_pending list with its own lock

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 hci_sock_get_channel+0x60/0x68 net/bluetooth/hci_sock.c:91
Read of size 2 at addr ffff0000c48885b2 by task syz.4.334/7318

CPU: 0 UID: 0 PID: 7318 Comm: syz.4.334 Not tainted 6.15.0-rc7-syzkaller-g187899f4124a #0 PREEMPT
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2025
Call trace:
show_stack+0x2c/0x3c arch/arm64/kernel/stacktrace.c:466 (C)
__dump_stack+0x30/0x40 lib/dump_stack.c:94
dump_stack_lvl+0xd8/0x12c lib/dump_stack.c:120
print_address_description+0xa8/0x254 mm/kasan/report.c:408
print_report+0x68/0x84 mm/kasan/report.c:521
kasan_report+0xb0/0x110 mm/kasan/report.c:634
__asan_report_load2_noabort+0x20/0x2c mm/kasan/report_generic.c:379
hci_sock_get_channel+0x60/0x68 net/bluetooth/hci_sock.c:91
mgmt_pending_find+0x7c/0x140 net/bluetooth/mgmt_util.c:223
pending_find net/bluetooth/mgmt.c:947 [inline]
remove_adv_monitor+0x44/0x1a4 net/bluetooth/mgmt.c:5445
hci_mgmt_cmd+0x780/0xc00 net/bluetooth/hci_sock.c:1712
hci_sock_sendmsg+0x544/0xbb0 net/bluetooth/hci_sock.c:1832
sock_sendmsg_nosec net/socket.c:712 [inline]
__sock_sendmsg net/socket.c:727 [inline]
sock_write_iter+0x25c/0x378 net/socket.c:1131
new_sync_write fs/read_write.c:591 [inline]
vfs_write+0x62c/0x97c fs/read_write.c:684
ksys_write+0x120/0x210 fs/read_write.c:736
__do_sys_write fs/read_write.c:747 [inline]
__se_sys_write fs/read_write.c:744 [inline]
__arm64_sys_write+0x7c/0x90 fs/read_write.c:744
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:49
el0_svc_common+0x130/0x23c arch/arm64/kernel/syscall.c:132
do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:151
el0_svc+0x58/0x17c arch/arm64/kernel/entry-common.c:767
el0t_64_sync_handler+0x78/0x108 arch/arm64/kernel/entry-common.c:786
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:600

Allocated by task 7037:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x40/0x78 mm/kasan/common.c:68
kasan_save_alloc_info+0x44/0x54 mm/kasan/generic.c:562
poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
__kasan_kmalloc+0x9c/0xb4 mm/kasan/common.c:394
kasan_kmalloc include/linux/kasan.h:260 [inline]
__do_kmalloc_node mm/slub.c:4327 [inline]
__kmalloc_noprof+0x2fc/0x4c8 mm/slub.c:4339
kmalloc_noprof include/linux/slab.h:909 [inline]
sk_prot_alloc+0xc4/0x1f0 net/core/sock.c:2198
sk_alloc+0x44/0x3ac net/core/sock.c:2254
bt_sock_alloc+0x4c/0x300 net/bluetooth/af_bluetooth.c:148
hci_sock_create+0xa8/0x194 net/bluetooth/hci_sock.c:2202
bt_sock_create+0x14c/0x24c net/bluetooth/af_bluetooth.c:132
__sock_create+0x43c/0x91c net/socket.c:1541
sock_create net/socket.c:1599 [inline]
__sys_socket_create net/socket.c:1636 [inline]
__sys_socket+0xd4/0x1c0 net/socket.c:1683
__do_sys_socket net/socket.c:1697 [inline]
__se_sys_socket net/socket.c:1695 [inline]
__arm64_sys_socket+0x7c/0x94 net/socket.c:1695
__invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
invoke_syscall+0x98/0x2b8 arch/arm64/kernel/syscall.c:49
el0_svc_common+0x130/0x23c arch/arm64/kernel/syscall.c:132
do_el0_svc+0x48/0x58 arch/arm64/kernel/syscall.c:151
el0_svc+0x58/0x17c arch/arm64/kernel/entry-common.c:767
el0t_64_sync_handler+0x78/0x108 arch/arm64/kernel/entry-common.c:786
el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:600

Freed by task 6607:
kasan_save_stack mm/kasan/common.c:47 [inline]
kasan_save_track+0x40/0x78 mm/kasan/common.c:68
kasan_save_free_info+0x58/0x70 mm/kasan/generic.c:576
poison_slab_object mm/kasan/common.c:247 [inline]
__kasan_slab_free+0x68/0x88 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+0x17c/0x474 mm/slub.c:4841
sk_prot_free net/core/sock.c:2237 [inline]
__sk_destruct+0x4f4/0x760 net/core/sock.c:2332
sk_destruct net/core/sock.c:2360 [inline]
__sk_free+0x320/0x430 net/core/sock.c:2371
sk_free+0x60/0xc8 net/core/sock.c:2382
sock_put include/net/sock.h:1944 [inline]
mgmt_pending_free+0x88/0x118 net/bluetooth/mgmt_util.c:290
mgmt_pending_remove+0xec/0x104 net/bluetooth/mgmt_util.c:298
mgmt_set_powered_complete+0x418/0x5cc net/bluetooth/mgmt.c:1355
hci_cmd_sync_work+0x204/0x33c net/bluetooth/hci_sync.c:334
process_one_work+0x7e8/0x156c kernel/workqueue.c:3238
process_scheduled_works kernel/workqueue.c:3319 [inline]
worker_thread+0x958/0xed8 kernel/workqueue.c:3400
kthread+0x5fc/0x75c kernel/kthread.c:464
ret_from_fork+0x10/0x20 arch/arm64/kernel/entry.S:847

Fixes: a380b6cff1a2 ("Bluetooth: Add generic mgmt helper API")
Closes: https://syzkaller.appspot.com/bug?extid=0a7039d5d9986ff4ecec
Closes: https://syzkaller.appspot.com/bug?extid=cc0cc52e7f43dc9e6df1
Reported-by: syzbot+0a7039d5d9986ff4ecec@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>

+80 -59
+1
include/net/bluetooth/hci_core.h
··· 546 546 struct hci_conn_hash conn_hash; 547 547 548 548 struct list_head mesh_pending; 549 + struct mutex mgmt_pending_lock; 549 550 struct list_head mgmt_pending; 550 551 struct list_head reject_list; 551 552 struct list_head accept_list;
+1
net/bluetooth/hci_core.c
··· 2485 2485 2486 2486 mutex_init(&hdev->lock); 2487 2487 mutex_init(&hdev->req_lock); 2488 + mutex_init(&hdev->mgmt_pending_lock); 2488 2489 2489 2490 ida_init(&hdev->unset_handle_ida); 2490 2491
+49 -52
net/bluetooth/mgmt.c
··· 1447 1447 1448 1448 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev); 1449 1449 1450 - list_del(&cmd->list); 1451 - 1452 1450 if (match->sk == NULL) { 1453 1451 match->sk = cmd->sk; 1454 1452 sock_hold(match->sk); 1455 1453 } 1456 - 1457 - mgmt_pending_free(cmd); 1458 1454 } 1459 1455 1460 1456 static void cmd_status_rsp(struct mgmt_pending_cmd *cmd, void *data) 1461 1457 { 1462 1458 u8 *status = data; 1463 1459 1464 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, *status); 1465 - mgmt_pending_remove(cmd); 1460 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, *status); 1466 1461 } 1467 1462 1468 1463 static void cmd_complete_rsp(struct mgmt_pending_cmd *cmd, void *data) ··· 1471 1476 1472 1477 if (cmd->cmd_complete) { 1473 1478 cmd->cmd_complete(cmd, match->mgmt_status); 1474 - mgmt_pending_remove(cmd); 1475 - 1476 1479 return; 1477 1480 } 1478 1481 ··· 1479 1486 1480 1487 static int generic_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) 1481 1488 { 1482 - return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, 1489 + return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, 1483 1490 cmd->param, cmd->param_len); 1484 1491 } 1485 1492 1486 1493 static int addr_cmd_complete(struct mgmt_pending_cmd *cmd, u8 status) 1487 1494 { 1488 - return mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, 1495 + return mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, 1489 1496 cmd->param, sizeof(struct mgmt_addr_info)); 1490 1497 } 1491 1498 ··· 1525 1532 1526 1533 if (err) { 1527 1534 u8 mgmt_err = mgmt_status(err); 1528 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 1535 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 1529 1536 hci_dev_clear_flag(hdev, HCI_LIMITED_DISCOVERABLE); 1530 1537 goto done; 1531 1538 } ··· 1700 1707 1701 1708 if (err) { 1702 1709 u8 mgmt_err = mgmt_status(err); 1703 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 1710 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 1704 1711 goto done; 1705 1712 } 1706 1713 ··· 1936 1943 new_settings(hdev, NULL); 1937 1944 } 1938 1945 1939 - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp, 1940 - &mgmt_err); 1946 + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, 1947 + cmd_status_rsp, &mgmt_err); 1941 1948 return; 1942 1949 } 1943 1950 ··· 1947 1954 changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); 1948 1955 } 1949 1956 1950 - mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); 1957 + mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, true, settings_rsp, &match); 1951 1958 1952 1959 if (changed) 1953 1960 new_settings(hdev, match.sk); ··· 2067 2074 bt_dev_dbg(hdev, "err %d", err); 2068 2075 2069 2076 if (status) { 2070 - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, 2071 - &status); 2077 + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, cmd_status_rsp, 2078 + &status); 2072 2079 return; 2073 2080 } 2074 2081 2075 - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match); 2082 + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, true, settings_rsp, &match); 2076 2083 2077 2084 new_settings(hdev, match.sk); 2078 2085 ··· 2131 2138 struct sock *sk = cmd->sk; 2132 2139 2133 2140 if (status) { 2134 - mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, 2141 + mgmt_pending_foreach(MGMT_OP_SET_MESH_RECEIVER, hdev, true, 2135 2142 cmd_status_rsp, &status); 2136 2143 return; 2137 2144 } ··· 2631 2638 2632 2639 bt_dev_dbg(hdev, "err %d", err); 2633 2640 2634 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 2641 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 2635 2642 mgmt_status(err), hdev->dev_class, 3); 2636 2643 2637 2644 mgmt_pending_free(cmd); ··· 3420 3427 bacpy(&rp.addr.bdaddr, &conn->dst); 3421 3428 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); 3422 3429 3423 - err = mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, 3430 + err = mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_PAIR_DEVICE, 3424 3431 status, &rp, sizeof(rp)); 3425 3432 3426 3433 /* So we don't get further callbacks for this connection */ ··· 5179 5186 hci_update_passive_scan(hdev); 5180 5187 } 5181 5188 5182 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 5189 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 5183 5190 mgmt_status(status), &rp, sizeof(rp)); 5184 5191 mgmt_pending_remove(cmd); 5185 5192 ··· 5394 5401 hci_update_passive_scan(hdev); 5395 5402 } 5396 5403 5397 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 5404 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 5398 5405 mgmt_status(status), &rp, sizeof(rp)); 5399 5406 mgmt_pending_free(cmd); 5400 5407 ··· 5770 5777 cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev)) 5771 5778 return; 5772 5779 5773 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), 5780 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), 5774 5781 cmd->param, 1); 5775 5782 mgmt_pending_remove(cmd); 5776 5783 ··· 5991 5998 5992 5999 bt_dev_dbg(hdev, "err %d", err); 5993 6000 5994 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err), 6001 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_status(err), 5995 6002 cmd->param, 1); 5996 6003 mgmt_pending_remove(cmd); 5997 6004 ··· 6216 6223 u8 status = mgmt_status(err); 6217 6224 6218 6225 if (status) { 6219 - mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, 6226 + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, 6220 6227 cmd_status_rsp, &status); 6221 6228 return; 6222 6229 } ··· 6226 6233 else 6227 6234 hci_dev_clear_flag(hdev, HCI_ADVERTISING); 6228 6235 6229 - mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp, 6236 + mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, true, settings_rsp, 6230 6237 &match); 6231 6238 6232 6239 new_settings(hdev, match.sk); ··· 6570 6577 */ 6571 6578 hci_dev_clear_flag(hdev, HCI_BREDR_ENABLED); 6572 6579 6573 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 6580 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 6574 6581 } else { 6575 6582 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev); 6576 6583 new_settings(hdev, cmd->sk); ··· 6707 6714 if (err) { 6708 6715 u8 mgmt_err = mgmt_status(err); 6709 6716 6710 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err); 6717 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err); 6711 6718 goto done; 6712 6719 } 6713 6720 ··· 7154 7161 rp.max_tx_power = HCI_TX_POWER_INVALID; 7155 7162 } 7156 7163 7157 - mgmt_cmd_complete(cmd->sk, cmd->index, MGMT_OP_GET_CONN_INFO, status, 7164 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status, 7158 7165 &rp, sizeof(rp)); 7159 7166 7160 7167 mgmt_pending_free(cmd); ··· 7314 7321 } 7315 7322 7316 7323 complete: 7317 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, status, &rp, 7324 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp, 7318 7325 sizeof(rp)); 7319 7326 7320 7327 mgmt_pending_free(cmd); ··· 8564 8571 rp.instance = cp->instance; 8565 8572 8566 8573 if (err) 8567 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 8574 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 8568 8575 mgmt_status(err)); 8569 8576 else 8570 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 8577 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 8571 8578 mgmt_status(err), &rp, sizeof(rp)); 8572 8579 8573 8580 add_adv_complete(hdev, cmd->sk, cp->instance, err); ··· 8755 8762 8756 8763 hci_remove_adv_instance(hdev, cp->instance); 8757 8764 8758 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 8765 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 8759 8766 mgmt_status(err)); 8760 8767 } else { 8761 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 8768 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 8762 8769 mgmt_status(err), &rp, sizeof(rp)); 8763 8770 } 8764 8771 ··· 8905 8912 rp.instance = cp->instance; 8906 8913 8907 8914 if (err) 8908 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 8915 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 8909 8916 mgmt_status(err)); 8910 8917 else 8911 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 8918 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 8912 8919 mgmt_status(err), &rp, sizeof(rp)); 8913 8920 8914 8921 mgmt_pending_free(cmd); ··· 9067 9074 rp.instance = cp->instance; 9068 9075 9069 9076 if (err) 9070 - mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, 9077 + mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, 9071 9078 mgmt_status(err)); 9072 9079 else 9073 - mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, 9080 + mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, 9074 9081 MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); 9075 9082 9076 9083 mgmt_pending_free(cmd); ··· 9342 9349 if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks)) 9343 9350 return; 9344 9351 9345 - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); 9352 + mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); 9346 9353 9347 9354 if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) { 9348 9355 mgmt_index_event(MGMT_EV_UNCONF_INDEX_REMOVED, hdev, NULL, 0, ··· 9380 9387 hci_update_passive_scan(hdev); 9381 9388 } 9382 9389 9383 - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); 9390 + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, 9391 + &match); 9384 9392 9385 9393 new_settings(hdev, match.sk); 9386 9394 ··· 9396 9402 struct cmd_lookup match = { NULL, hdev }; 9397 9403 u8 zero_cod[] = { 0, 0, 0 }; 9398 9404 9399 - mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match); 9405 + mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, true, settings_rsp, 9406 + &match); 9400 9407 9401 9408 /* If the power off is because of hdev unregistration let 9402 9409 * use the appropriate INVALID_INDEX status. Otherwise use ··· 9411 9416 else 9412 9417 match.mgmt_status = MGMT_STATUS_NOT_POWERED; 9413 9418 9414 - mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &match); 9419 + mgmt_pending_foreach(0, hdev, true, cmd_complete_rsp, &match); 9415 9420 9416 9421 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) { 9417 9422 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, ··· 9652 9657 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk); 9653 9658 9654 9659 cmd->cmd_complete(cmd, 0); 9655 - mgmt_pending_remove(cmd); 9656 9660 } 9657 9661 9658 9662 bool mgmt_powering_down(struct hci_dev *hdev) ··· 9707 9713 struct mgmt_cp_disconnect *cp; 9708 9714 struct mgmt_pending_cmd *cmd; 9709 9715 9710 - mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, 9711 - hdev); 9716 + mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, true, 9717 + unpair_device_rsp, hdev); 9712 9718 9713 9719 cmd = pending_find(MGMT_OP_DISCONNECT, hdev); 9714 9720 if (!cmd) ··· 9901 9907 9902 9908 if (status) { 9903 9909 u8 mgmt_err = mgmt_status(status); 9904 - mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, 9910 + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, 9905 9911 cmd_status_rsp, &mgmt_err); 9906 9912 return; 9907 9913 } ··· 9911 9917 else 9912 9918 changed = hci_dev_test_and_clear_flag(hdev, HCI_LINK_SECURITY); 9913 9919 9914 - mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp, 9915 - &match); 9920 + mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, true, 9921 + settings_rsp, &match); 9916 9922 9917 9923 if (changed) 9918 9924 new_settings(hdev, match.sk); ··· 9936 9942 { 9937 9943 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) }; 9938 9944 9939 - mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match); 9940 - mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match); 9941 - mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match); 9945 + mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, false, sk_lookup, 9946 + &match); 9947 + mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, false, sk_lookup, 9948 + &match); 9949 + mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, false, sk_lookup, 9950 + &match); 9942 9951 9943 9952 if (!status) { 9944 9953 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
+27 -5
net/bluetooth/mgmt_util.c
··· 217 217 struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, 218 218 struct hci_dev *hdev) 219 219 { 220 - struct mgmt_pending_cmd *cmd; 220 + struct mgmt_pending_cmd *cmd, *tmp; 221 221 222 - list_for_each_entry(cmd, &hdev->mgmt_pending, list) { 222 + mutex_lock(&hdev->mgmt_pending_lock); 223 + 224 + list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { 223 225 if (hci_sock_get_channel(cmd->sk) != channel) 224 226 continue; 225 - if (cmd->opcode == opcode) 227 + 228 + if (cmd->opcode == opcode) { 229 + mutex_unlock(&hdev->mgmt_pending_lock); 226 230 return cmd; 231 + } 227 232 } 233 + 234 + mutex_unlock(&hdev->mgmt_pending_lock); 228 235 229 236 return NULL; 230 237 } 231 238 232 - void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 239 + void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, 233 240 void (*cb)(struct mgmt_pending_cmd *cmd, void *data), 234 241 void *data) 235 242 { 236 243 struct mgmt_pending_cmd *cmd, *tmp; 237 244 245 + mutex_lock(&hdev->mgmt_pending_lock); 246 + 238 247 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) { 239 248 if (opcode > 0 && cmd->opcode != opcode) 240 249 continue; 241 250 251 + if (remove) 252 + list_del(&cmd->list); 253 + 242 254 cb(cmd, data); 255 + 256 + if (remove) 257 + mgmt_pending_free(cmd); 243 258 } 259 + 260 + mutex_unlock(&hdev->mgmt_pending_lock); 244 261 } 245 262 246 263 struct mgmt_pending_cmd *mgmt_pending_new(struct sock *sk, u16 opcode, ··· 271 254 return NULL; 272 255 273 256 cmd->opcode = opcode; 274 - cmd->index = hdev->id; 257 + cmd->hdev = hdev; 275 258 276 259 cmd->param = kmemdup(data, len, GFP_KERNEL); 277 260 if (!cmd->param) { ··· 297 280 if (!cmd) 298 281 return NULL; 299 282 283 + mutex_lock(&hdev->mgmt_pending_lock); 300 284 list_add_tail(&cmd->list, &hdev->mgmt_pending); 285 + mutex_unlock(&hdev->mgmt_pending_lock); 301 286 302 287 return cmd; 303 288 } ··· 313 294 314 295 void mgmt_pending_remove(struct mgmt_pending_cmd *cmd) 315 296 { 297 + mutex_lock(&cmd->hdev->mgmt_pending_lock); 316 298 list_del(&cmd->list); 299 + mutex_unlock(&cmd->hdev->mgmt_pending_lock); 300 + 317 301 mgmt_pending_free(cmd); 318 302 } 319 303
+2 -2
net/bluetooth/mgmt_util.h
··· 33 33 struct mgmt_pending_cmd { 34 34 struct list_head list; 35 35 u16 opcode; 36 - int index; 36 + struct hci_dev *hdev; 37 37 void *param; 38 38 size_t param_len; 39 39 struct sock *sk; ··· 54 54 55 55 struct mgmt_pending_cmd *mgmt_pending_find(unsigned short channel, u16 opcode, 56 56 struct hci_dev *hdev); 57 - void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, 57 + void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, bool remove, 58 58 void (*cb)(struct mgmt_pending_cmd *cmd, void *data), 59 59 void *data); 60 60 struct mgmt_pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,