Skip to content

Commit 89e856e

Browse files
ea1davisVudentz
authored andcommitted
bluetooth/l2cap: sync sock recv cb and release
The problem occurs between the system call to close the sock and hci_rx_work, where the former releases the sock and the latter accesses it without lock protection. CPU0 CPU1 ---- ---- sock_close hci_rx_work l2cap_sock_release hci_acldata_packet l2cap_sock_kill l2cap_recv_frame sk_free l2cap_conless_channel l2cap_sock_recv_cb If hci_rx_work processes the data that needs to be received before the sock is closed, then everything is normal; Otherwise, the work thread may access the released sock when receiving data. Add a chan mutex in the rx callback of the sock to achieve synchronization between the sock release and recv cb. Sock is dead, so set chan data to NULL, avoid others use invalid sock pointer. Reported-and-tested-by: [email protected] Signed-off-by: Edward Adam Davis <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent 015d79c commit 89e856e

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

net/bluetooth/l2cap_sock.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,10 @@ static void l2cap_sock_kill(struct sock *sk)
12391239

12401240
BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state));
12411241

1242+
/* Sock is dead, so set chan data to NULL, avoid other task use invalid
1243+
* sock pointer.
1244+
*/
1245+
l2cap_pi(sk)->chan->data = NULL;
12421246
/* Kill poor orphan */
12431247

12441248
l2cap_chan_put(l2cap_pi(sk)->chan);
@@ -1481,12 +1485,25 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
14811485

14821486
static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
14831487
{
1484-
struct sock *sk = chan->data;
1485-
struct l2cap_pinfo *pi = l2cap_pi(sk);
1488+
struct sock *sk;
1489+
struct l2cap_pinfo *pi;
14861490
int err;
14871491

1488-
lock_sock(sk);
1492+
/* To avoid race with sock_release, a chan lock needs to be added here
1493+
* to synchronize the sock.
1494+
*/
1495+
l2cap_chan_hold(chan);
1496+
l2cap_chan_lock(chan);
1497+
sk = chan->data;
14891498

1499+
if (!sk) {
1500+
l2cap_chan_unlock(chan);
1501+
l2cap_chan_put(chan);
1502+
return -ENXIO;
1503+
}
1504+
1505+
pi = l2cap_pi(sk);
1506+
lock_sock(sk);
14901507
if (chan->mode == L2CAP_MODE_ERTM && !list_empty(&pi->rx_busy)) {
14911508
err = -ENOMEM;
14921509
goto done;
@@ -1535,6 +1552,8 @@ static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
15351552

15361553
done:
15371554
release_sock(sk);
1555+
l2cap_chan_unlock(chan);
1556+
l2cap_chan_put(chan);
15381557

15391558
return err;
15401559
}

0 commit comments

Comments
 (0)