Skip to content

Commit b6807cf

Browse files
Cen ZhangVudentz
authored andcommitted
Bluetooth: hci_sync: annotate data-races around hdev->req_status
__hci_cmd_sync_sk() sets hdev->req_status under hdev->req_lock: hdev->req_status = HCI_REQ_PEND; However, several other functions read or write hdev->req_status without holding any lock: - hci_send_cmd_sync() reads req_status in hci_cmd_work (workqueue) - hci_cmd_sync_complete() reads/writes from HCI event completion - hci_cmd_sync_cancel() / hci_cmd_sync_cancel_sync() read/write - hci_abort_conn() reads in connection abort path Since __hci_cmd_sync_sk() runs on hdev->req_workqueue while hci_send_cmd_sync() runs on hdev->workqueue, these are different workqueues that can execute concurrently on different CPUs. The plain C accesses constitute a data race. Add READ_ONCE()/WRITE_ONCE() annotations on all concurrent accesses to hdev->req_status to prevent potential compiler optimizations that could affect correctness (e.g., load fusing in the wait_event condition or store reordering). Signed-off-by: Cen Zhang <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 5f5fa4c commit b6807cf

3 files changed

Lines changed: 12 additions & 12 deletions

File tree

net/bluetooth/hci_conn.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3095,7 +3095,7 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
30953095
* hci_connect_le serializes the connection attempts so only one
30963096
* connection can be in BT_CONNECT at time.
30973097
*/
3098-
if (conn->state == BT_CONNECT && hdev->req_status == HCI_REQ_PEND) {
3098+
if (conn->state == BT_CONNECT && READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
30993099
switch (hci_skb_event(hdev->sent_cmd)) {
31003100
case HCI_EV_CONN_COMPLETE:
31013101
case HCI_EV_LE_CONN_COMPLETE:

net/bluetooth/hci_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4126,7 +4126,7 @@ static int hci_send_cmd_sync(struct hci_dev *hdev, struct sk_buff *skb)
41264126
kfree_skb(skb);
41274127
}
41284128

4129-
if (hdev->req_status == HCI_REQ_PEND &&
4129+
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND &&
41304130
!hci_dev_test_and_set_flag(hdev, HCI_CMD_PENDING)) {
41314131
kfree_skb(hdev->req_skb);
41324132
hdev->req_skb = skb_clone(hdev->sent_cmd, GFP_KERNEL);

net/bluetooth/hci_sync.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
2525
{
2626
bt_dev_dbg(hdev, "result 0x%2.2x", result);
2727

28-
if (hdev->req_status != HCI_REQ_PEND)
28+
if (READ_ONCE(hdev->req_status) != HCI_REQ_PEND)
2929
return;
3030

3131
hdev->req_result = result;
32-
hdev->req_status = HCI_REQ_DONE;
32+
WRITE_ONCE(hdev->req_status, HCI_REQ_DONE);
3333

3434
/* Free the request command so it is not used as response */
3535
kfree_skb(hdev->req_skb);
@@ -167,20 +167,20 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
167167

168168
hci_cmd_sync_add(&req, opcode, plen, param, event, sk);
169169

170-
hdev->req_status = HCI_REQ_PEND;
170+
WRITE_ONCE(hdev->req_status, HCI_REQ_PEND);
171171

172172
err = hci_req_sync_run(&req);
173173
if (err < 0)
174174
return ERR_PTR(err);
175175

176176
err = wait_event_interruptible_timeout(hdev->req_wait_q,
177-
hdev->req_status != HCI_REQ_PEND,
177+
READ_ONCE(hdev->req_status) != HCI_REQ_PEND,
178178
timeout);
179179

180180
if (err == -ERESTARTSYS)
181181
return ERR_PTR(-EINTR);
182182

183-
switch (hdev->req_status) {
183+
switch (READ_ONCE(hdev->req_status)) {
184184
case HCI_REQ_DONE:
185185
err = -bt_to_errno(hdev->req_result);
186186
break;
@@ -194,7 +194,7 @@ struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
194194
break;
195195
}
196196

197-
hdev->req_status = 0;
197+
WRITE_ONCE(hdev->req_status, 0);
198198
hdev->req_result = 0;
199199
skb = hdev->req_rsp;
200200
hdev->req_rsp = NULL;
@@ -665,9 +665,9 @@ void hci_cmd_sync_cancel(struct hci_dev *hdev, int err)
665665
{
666666
bt_dev_dbg(hdev, "err 0x%2.2x", err);
667667

668-
if (hdev->req_status == HCI_REQ_PEND) {
668+
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
669669
hdev->req_result = err;
670-
hdev->req_status = HCI_REQ_CANCELED;
670+
WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);
671671

672672
queue_work(hdev->workqueue, &hdev->cmd_sync_cancel_work);
673673
}
@@ -683,12 +683,12 @@ void hci_cmd_sync_cancel_sync(struct hci_dev *hdev, int err)
683683
{
684684
bt_dev_dbg(hdev, "err 0x%2.2x", err);
685685

686-
if (hdev->req_status == HCI_REQ_PEND) {
686+
if (READ_ONCE(hdev->req_status) == HCI_REQ_PEND) {
687687
/* req_result is __u32 so error must be positive to be properly
688688
* propagated.
689689
*/
690690
hdev->req_result = err < 0 ? -err : err;
691-
hdev->req_status = HCI_REQ_CANCELED;
691+
WRITE_ONCE(hdev->req_status, HCI_REQ_CANCELED);
692692

693693
wake_up_interruptible(&hdev->req_wait_q);
694694
}

0 commit comments

Comments
 (0)