Skip to content

Commit 195ef75

Browse files
pvVudentz
authored andcommitted
Bluetooth: use RCU for hci_conn_params and iterate safely in hci_sync
hci_update_accept_list_sync iterates over hdev->pend_le_conns and hdev->pend_le_reports, and waits for controller events in the loop body, without holding hdev lock. Meanwhile, these lists and the items may be modified e.g. by le_scan_cleanup. This can invalidate the list cursor or any other item in the list, resulting to invalid behavior (eg use-after-free). Use RCU for the hci_conn_params action lists. Since the loop bodies in hci_sync block and we cannot use RCU or hdev->lock for the whole loop, copy list items first and then iterate on the copy. Only the flags field is written from elsewhere, so READ_ONCE/WRITE_ONCE should guarantee we read valid values. Free params everywhere with hci_conn_params_free so the cleanup is guaranteed to be done properly. This fixes the following, which can be triggered e.g. by BlueZ new mgmt-tester case "Add + Remove Device Nowait - Success", or by changing hci_le_set_cig_params to always return false, and running iso-tester: ================================================================== BUG: KASAN: slab-use-after-free in hci_update_passive_scan_sync (net/bluetooth/hci_sync.c:2536 net/bluetooth/hci_sync.c:2723 net/bluetooth/hci_sync.c:2841) Read of size 8 at addr ffff888001265018 by task kworker/u3:0/32 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-1.fc38 04/01/2014 Workqueue: hci0 hci_cmd_sync_work Call Trace: <TASK> dump_stack_lvl (./arch/x86/include/asm/irqflags.h:134 lib/dump_stack.c:107) print_report (mm/kasan/report.c:320 mm/kasan/report.c:430) ? __virt_addr_valid (./include/linux/mmzone.h:1915 ./include/linux/mmzone.h:2011 arch/x86/mm/physaddr.c:65) ? hci_update_passive_scan_sync (net/bluetooth/hci_sync.c:2536 net/bluetooth/hci_sync.c:2723 net/bluetooth/hci_sync.c:2841) kasan_report (mm/kasan/report.c:538) ? hci_update_passive_scan_sync (net/bluetooth/hci_sync.c:2536 net/bluetooth/hci_sync.c:2723 net/bluetooth/hci_sync.c:2841) hci_update_passive_scan_sync (net/bluetooth/hci_sync.c:2536 net/bluetooth/hci_sync.c:2723 net/bluetooth/hci_sync.c:2841) ? __pfx_hci_update_passive_scan_sync (net/bluetooth/hci_sync.c:2780) ? mutex_lock (kernel/locking/mutex.c:282) ? __pfx_mutex_lock (kernel/locking/mutex.c:282) ? __pfx_mutex_unlock (kernel/locking/mutex.c:538) ? __pfx_update_passive_scan_sync (net/bluetooth/hci_sync.c:2861) hci_cmd_sync_work (net/bluetooth/hci_sync.c:306) process_one_work (./arch/x86/include/asm/preempt.h:27 kernel/workqueue.c:2399) worker_thread (./include/linux/list.h:292 kernel/workqueue.c:2538) ? __pfx_worker_thread (kernel/workqueue.c:2480) kthread (kernel/kthread.c:376) ? __pfx_kthread (kernel/kthread.c:331) ret_from_fork (arch/x86/entry/entry_64.S:314) </TASK> Allocated by task 31: kasan_save_stack (mm/kasan/common.c:46) kasan_set_track (mm/kasan/common.c:52) __kasan_kmalloc (mm/kasan/common.c:374 mm/kasan/common.c:383) hci_conn_params_add (./include/linux/slab.h:580 ./include/linux/slab.h:720 net/bluetooth/hci_core.c:2277) hci_connect_le_scan (net/bluetooth/hci_conn.c:1419 net/bluetooth/hci_conn.c:1589) hci_connect_cis (net/bluetooth/hci_conn.c:2266) iso_connect_cis (net/bluetooth/iso.c:390) iso_sock_connect (net/bluetooth/iso.c:899) __sys_connect (net/socket.c:2003 net/socket.c:2020) __x64_sys_connect (net/socket.c:2027) do_syscall_64 (arch/x86/entry/common.c:50 arch/x86/entry/common.c:80) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:120) Freed by task 15: kasan_save_stack (mm/kasan/common.c:46) kasan_set_track (mm/kasan/common.c:52) kasan_save_free_info (mm/kasan/generic.c:523) __kasan_slab_free (mm/kasan/common.c:238 mm/kasan/common.c:200 mm/kasan/common.c:244) __kmem_cache_free (mm/slub.c:1807 mm/slub.c:3787 mm/slub.c:3800) hci_conn_params_del (net/bluetooth/hci_core.c:2323) le_scan_cleanup (net/bluetooth/hci_conn.c:202) process_one_work (./arch/x86/include/asm/preempt.h:27 kernel/workqueue.c:2399) worker_thread (./include/linux/list.h:292 kernel/workqueue.c:2538) kthread (kernel/kthread.c:376) ret_from_fork (arch/x86/entry/entry_64.S:314) ================================================================== Fixes: e8907f7 ("Bluetooth: hci_sync: Make use of hci_cmd_sync_queue set 3") Signed-off-by: Pauli Virtanen <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent ac52864 commit 195ef75

File tree

6 files changed

+164
-44
lines changed

6 files changed

+164
-44
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,7 @@ struct hci_conn_params {
822822

823823
struct hci_conn *conn;
824824
bool explicit_connect;
825+
/* Accessed without hdev->lock: */
825826
hci_conn_flags_t flags;
826827
u8 privacy_mode;
827828
};
@@ -1573,7 +1574,11 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
15731574
bdaddr_t *addr, u8 addr_type);
15741575
void hci_conn_params_del(struct hci_dev *hdev, bdaddr_t *addr, u8 addr_type);
15751576
void hci_conn_params_clear_disabled(struct hci_dev *hdev);
1577+
void hci_conn_params_free(struct hci_conn_params *param);
15761578

1579+
void hci_pend_le_list_del_init(struct hci_conn_params *param);
1580+
void hci_pend_le_list_add(struct hci_conn_params *param,
1581+
struct list_head *list);
15771582
struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
15781583
bdaddr_t *addr,
15791584
u8 addr_type);

net/bluetooth/hci_conn.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ static void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
118118
*/
119119
params->explicit_connect = false;
120120

121-
list_del_init(&params->action);
121+
hci_pend_le_list_del_init(params);
122122

123123
switch (params->auto_connect) {
124124
case HCI_AUTO_CONN_EXPLICIT:
@@ -127,10 +127,10 @@ static void hci_connect_le_scan_cleanup(struct hci_conn *conn, u8 status)
127127
return;
128128
case HCI_AUTO_CONN_DIRECT:
129129
case HCI_AUTO_CONN_ALWAYS:
130-
list_add(&params->action, &hdev->pend_le_conns);
130+
hci_pend_le_list_add(params, &hdev->pend_le_conns);
131131
break;
132132
case HCI_AUTO_CONN_REPORT:
133-
list_add(&params->action, &hdev->pend_le_reports);
133+
hci_pend_le_list_add(params, &hdev->pend_le_reports);
134134
break;
135135
default:
136136
break;
@@ -1426,8 +1426,8 @@ static int hci_explicit_conn_params_set(struct hci_dev *hdev,
14261426
if (params->auto_connect == HCI_AUTO_CONN_DISABLED ||
14271427
params->auto_connect == HCI_AUTO_CONN_REPORT ||
14281428
params->auto_connect == HCI_AUTO_CONN_EXPLICIT) {
1429-
list_del_init(&params->action);
1430-
list_add(&params->action, &hdev->pend_le_conns);
1429+
hci_pend_le_list_del_init(params);
1430+
hci_pend_le_list_add(params, &hdev->pend_le_conns);
14311431
}
14321432

14331433
params->explicit_connect = true;

net/bluetooth/hci_core.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2249,21 +2249,45 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
22492249
return NULL;
22502250
}
22512251

2252-
/* This function requires the caller holds hdev->lock */
2252+
/* This function requires the caller holds hdev->lock or rcu_read_lock */
22532253
struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list,
22542254
bdaddr_t *addr, u8 addr_type)
22552255
{
22562256
struct hci_conn_params *param;
22572257

2258-
list_for_each_entry(param, list, action) {
2258+
rcu_read_lock();
2259+
2260+
list_for_each_entry_rcu(param, list, action) {
22592261
if (bacmp(&param->addr, addr) == 0 &&
2260-
param->addr_type == addr_type)
2262+
param->addr_type == addr_type) {
2263+
rcu_read_unlock();
22612264
return param;
2265+
}
22622266
}
22632267

2268+
rcu_read_unlock();
2269+
22642270
return NULL;
22652271
}
22662272

2273+
/* This function requires the caller holds hdev->lock */
2274+
void hci_pend_le_list_del_init(struct hci_conn_params *param)
2275+
{
2276+
if (list_empty(&param->action))
2277+
return;
2278+
2279+
list_del_rcu(&param->action);
2280+
synchronize_rcu();
2281+
INIT_LIST_HEAD(&param->action);
2282+
}
2283+
2284+
/* This function requires the caller holds hdev->lock */
2285+
void hci_pend_le_list_add(struct hci_conn_params *param,
2286+
struct list_head *list)
2287+
{
2288+
list_add_rcu(&param->action, list);
2289+
}
2290+
22672291
/* This function requires the caller holds hdev->lock */
22682292
struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
22692293
bdaddr_t *addr, u8 addr_type)
@@ -2297,14 +2321,15 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev,
22972321
return params;
22982322
}
22992323

2300-
static void hci_conn_params_free(struct hci_conn_params *params)
2324+
void hci_conn_params_free(struct hci_conn_params *params)
23012325
{
2326+
hci_pend_le_list_del_init(params);
2327+
23022328
if (params->conn) {
23032329
hci_conn_drop(params->conn);
23042330
hci_conn_put(params->conn);
23052331
}
23062332

2307-
list_del(&params->action);
23082333
list_del(&params->list);
23092334
kfree(params);
23102335
}
@@ -2342,8 +2367,7 @@ void hci_conn_params_clear_disabled(struct hci_dev *hdev)
23422367
continue;
23432368
}
23442369

2345-
list_del(&params->list);
2346-
kfree(params);
2370+
hci_conn_params_free(params);
23472371
}
23482372

23492373
BT_DBG("All LE disabled connection parameters were removed");

net/bluetooth/hci_event.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ static u8 hci_cc_le_set_privacy_mode(struct hci_dev *hdev, void *data,
15641564

15651565
params = hci_conn_params_lookup(hdev, &cp->bdaddr, cp->bdaddr_type);
15661566
if (params)
1567-
params->privacy_mode = cp->mode;
1567+
WRITE_ONCE(params->privacy_mode, cp->mode);
15681568

15691569
hci_dev_unlock(hdev);
15701570

@@ -2804,8 +2804,8 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
28042804

28052805
case HCI_AUTO_CONN_DIRECT:
28062806
case HCI_AUTO_CONN_ALWAYS:
2807-
list_del_init(&params->action);
2808-
list_add(&params->action, &hdev->pend_le_conns);
2807+
hci_pend_le_list_del_init(params);
2808+
hci_pend_le_list_add(params, &hdev->pend_le_conns);
28092809
break;
28102810

28112811
default:
@@ -3423,8 +3423,8 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, void *data,
34233423

34243424
case HCI_AUTO_CONN_DIRECT:
34253425
case HCI_AUTO_CONN_ALWAYS:
3426-
list_del_init(&params->action);
3427-
list_add(&params->action, &hdev->pend_le_conns);
3426+
hci_pend_le_list_del_init(params);
3427+
hci_pend_le_list_add(params, &hdev->pend_le_conns);
34283428
hci_update_passive_scan(hdev);
34293429
break;
34303430

@@ -5962,7 +5962,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
59625962
params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst,
59635963
conn->dst_type);
59645964
if (params) {
5965-
list_del_init(&params->action);
5965+
hci_pend_le_list_del_init(params);
59665966
if (params->conn) {
59675967
hci_conn_drop(params->conn);
59685968
hci_conn_put(params->conn);

net/bluetooth/hci_sync.c

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2160,15 +2160,23 @@ static int hci_le_del_accept_list_sync(struct hci_dev *hdev,
21602160
return 0;
21612161
}
21622162

2163+
struct conn_params {
2164+
bdaddr_t addr;
2165+
u8 addr_type;
2166+
hci_conn_flags_t flags;
2167+
u8 privacy_mode;
2168+
};
2169+
21632170
/* Adds connection to resolve list if needed.
21642171
* Setting params to NULL programs local hdev->irk
21652172
*/
21662173
static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
2167-
struct hci_conn_params *params)
2174+
struct conn_params *params)
21682175
{
21692176
struct hci_cp_le_add_to_resolv_list cp;
21702177
struct smp_irk *irk;
21712178
struct bdaddr_list_with_irk *entry;
2179+
struct hci_conn_params *p;
21722180

21732181
if (!use_ll_privacy(hdev))
21742182
return 0;
@@ -2203,6 +2211,16 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
22032211
/* Default privacy mode is always Network */
22042212
params->privacy_mode = HCI_NETWORK_PRIVACY;
22052213

2214+
rcu_read_lock();
2215+
p = hci_pend_le_action_lookup(&hdev->pend_le_conns,
2216+
&params->addr, params->addr_type);
2217+
if (!p)
2218+
p = hci_pend_le_action_lookup(&hdev->pend_le_reports,
2219+
&params->addr, params->addr_type);
2220+
if (p)
2221+
WRITE_ONCE(p->privacy_mode, HCI_NETWORK_PRIVACY);
2222+
rcu_read_unlock();
2223+
22062224
done:
22072225
if (hci_dev_test_flag(hdev, HCI_PRIVACY))
22082226
memcpy(cp.local_irk, hdev->irk, 16);
@@ -2215,7 +2233,7 @@ static int hci_le_add_resolve_list_sync(struct hci_dev *hdev,
22152233

22162234
/* Set Device Privacy Mode. */
22172235
static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
2218-
struct hci_conn_params *params)
2236+
struct conn_params *params)
22192237
{
22202238
struct hci_cp_le_set_privacy_mode cp;
22212239
struct smp_irk *irk;
@@ -2240,6 +2258,8 @@ static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
22402258
bacpy(&cp.bdaddr, &irk->bdaddr);
22412259
cp.mode = HCI_DEVICE_PRIVACY;
22422260

2261+
/* Note: params->privacy_mode is not updated since it is a copy */
2262+
22432263
return __hci_cmd_sync_status(hdev, HCI_OP_LE_SET_PRIVACY_MODE,
22442264
sizeof(cp), &cp, HCI_CMD_TIMEOUT);
22452265
}
@@ -2249,7 +2269,7 @@ static int hci_le_set_privacy_mode_sync(struct hci_dev *hdev,
22492269
* properly set the privacy mode.
22502270
*/
22512271
static int hci_le_add_accept_list_sync(struct hci_dev *hdev,
2252-
struct hci_conn_params *params,
2272+
struct conn_params *params,
22532273
u8 *num_entries)
22542274
{
22552275
struct hci_cp_le_add_to_accept_list cp;
@@ -2447,6 +2467,52 @@ struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev,
24472467
return __hci_cmd_sync_sk(hdev, opcode, 0, NULL, 0, HCI_CMD_TIMEOUT, sk);
24482468
}
24492469

2470+
static struct conn_params *conn_params_copy(struct list_head *list, size_t *n)
2471+
{
2472+
struct hci_conn_params *params;
2473+
struct conn_params *p;
2474+
size_t i;
2475+
2476+
rcu_read_lock();
2477+
2478+
i = 0;
2479+
list_for_each_entry_rcu(params, list, action)
2480+
++i;
2481+
*n = i;
2482+
2483+
rcu_read_unlock();
2484+
2485+
p = kvcalloc(*n, sizeof(struct conn_params), GFP_KERNEL);
2486+
if (!p)
2487+
return NULL;
2488+
2489+
rcu_read_lock();
2490+
2491+
i = 0;
2492+
list_for_each_entry_rcu(params, list, action) {
2493+
/* Racing adds are handled in next scan update */
2494+
if (i >= *n)
2495+
break;
2496+
2497+
/* No hdev->lock, but: addr, addr_type are immutable.
2498+
* privacy_mode is only written by us or in
2499+
* hci_cc_le_set_privacy_mode that we wait for.
2500+
* We should be idempotent so MGMT updating flags
2501+
* while we are processing is OK.
2502+
*/
2503+
bacpy(&p[i].addr, &params->addr);
2504+
p[i].addr_type = params->addr_type;
2505+
p[i].flags = READ_ONCE(params->flags);
2506+
p[i].privacy_mode = READ_ONCE(params->privacy_mode);
2507+
++i;
2508+
}
2509+
2510+
rcu_read_unlock();
2511+
2512+
*n = i;
2513+
return p;
2514+
}
2515+
24502516
/* Device must not be scanning when updating the accept list.
24512517
*
24522518
* Update is done using the following sequence:
@@ -2466,11 +2532,12 @@ struct sk_buff *hci_read_local_oob_data_sync(struct hci_dev *hdev,
24662532
*/
24672533
static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
24682534
{
2469-
struct hci_conn_params *params;
2535+
struct conn_params *params;
24702536
struct bdaddr_list *b, *t;
24712537
u8 num_entries = 0;
24722538
bool pend_conn, pend_report;
24732539
u8 filter_policy;
2540+
size_t i, n;
24742541
int err;
24752542

24762543
/* Pause advertising if resolving list can be used as controllers
@@ -2504,6 +2571,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
25042571
if (hci_conn_hash_lookup_le(hdev, &b->bdaddr, b->bdaddr_type))
25052572
continue;
25062573

2574+
/* Pointers not dereferenced, no locks needed */
25072575
pend_conn = hci_pend_le_action_lookup(&hdev->pend_le_conns,
25082576
&b->bdaddr,
25092577
b->bdaddr_type);
@@ -2532,23 +2600,50 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
25322600
* available accept list entries in the controller, then
25332601
* just abort and return filer policy value to not use the
25342602
* accept list.
2603+
*
2604+
* The list and params may be mutated while we wait for events,
2605+
* so make a copy and iterate it.
25352606
*/
2536-
list_for_each_entry(params, &hdev->pend_le_conns, action) {
2537-
err = hci_le_add_accept_list_sync(hdev, params, &num_entries);
2538-
if (err)
2607+
2608+
params = conn_params_copy(&hdev->pend_le_conns, &n);
2609+
if (!params) {
2610+
err = -ENOMEM;
2611+
goto done;
2612+
}
2613+
2614+
for (i = 0; i < n; ++i) {
2615+
err = hci_le_add_accept_list_sync(hdev, &params[i],
2616+
&num_entries);
2617+
if (err) {
2618+
kvfree(params);
25392619
goto done;
2620+
}
25402621
}
25412622

2623+
kvfree(params);
2624+
25422625
/* After adding all new pending connections, walk through
25432626
* the list of pending reports and also add these to the
25442627
* accept list if there is still space. Abort if space runs out.
25452628
*/
2546-
list_for_each_entry(params, &hdev->pend_le_reports, action) {
2547-
err = hci_le_add_accept_list_sync(hdev, params, &num_entries);
2548-
if (err)
2629+
2630+
params = conn_params_copy(&hdev->pend_le_reports, &n);
2631+
if (!params) {
2632+
err = -ENOMEM;
2633+
goto done;
2634+
}
2635+
2636+
for (i = 0; i < n; ++i) {
2637+
err = hci_le_add_accept_list_sync(hdev, &params[i],
2638+
&num_entries);
2639+
if (err) {
2640+
kvfree(params);
25492641
goto done;
2642+
}
25502643
}
25512644

2645+
kvfree(params);
2646+
25522647
/* Use the allowlist unless the following conditions are all true:
25532648
* - We are not currently suspending
25542649
* - There are 1 or more ADV monitors registered and it's not offloaded
@@ -4837,12 +4932,12 @@ static void hci_pend_le_actions_clear(struct hci_dev *hdev)
48374932
struct hci_conn_params *p;
48384933

48394934
list_for_each_entry(p, &hdev->le_conn_params, list) {
4935+
hci_pend_le_list_del_init(p);
48404936
if (p->conn) {
48414937
hci_conn_drop(p->conn);
48424938
hci_conn_put(p->conn);
48434939
p->conn = NULL;
48444940
}
4845-
list_del_init(&p->action);
48464941
}
48474942

48484943
BT_DBG("All LE pending actions cleared");

0 commit comments

Comments
 (0)