Bluetooth: L2CAP: Fix potential user-after-free

This fixes all instances of which requires to allocate a buffer calling
alloc_skb which may release the chan lock and reacquire later which
makes it possible that the chan is disconnected in the meantime.

Fixes: a6a5568c ("Bluetooth: Lock the L2CAP channel when sending")
Reported-by: default avatarAlexander Coffin <alex.coffin@matician.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent 2394186a
...@@ -2683,14 +2683,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) ...@@ -2683,14 +2683,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
if (IS_ERR(skb)) if (IS_ERR(skb))
return PTR_ERR(skb); return PTR_ERR(skb);
/* Channel lock is released before requesting new skb and then
* reacquired thus we need to recheck channel state.
*/
if (chan->state != BT_CONNECTED) {
kfree_skb(skb);
return -ENOTCONN;
}
l2cap_do_send(chan, skb); l2cap_do_send(chan, skb);
return len; return len;
} }
...@@ -2735,14 +2727,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) ...@@ -2735,14 +2727,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
if (IS_ERR(skb)) if (IS_ERR(skb))
return PTR_ERR(skb); return PTR_ERR(skb);
/* Channel lock is released before requesting new skb and then
* reacquired thus we need to recheck channel state.
*/
if (chan->state != BT_CONNECTED) {
kfree_skb(skb);
return -ENOTCONN;
}
l2cap_do_send(chan, skb); l2cap_do_send(chan, skb);
err = len; err = len;
break; break;
...@@ -2763,14 +2747,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len) ...@@ -2763,14 +2747,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
*/ */
err = l2cap_segment_sdu(chan, &seg_queue, msg, len); err = l2cap_segment_sdu(chan, &seg_queue, msg, len);
/* The channel could have been closed while segmenting,
* check that it is still connected.
*/
if (chan->state != BT_CONNECTED) {
__skb_queue_purge(&seg_queue);
err = -ENOTCONN;
}
if (err) if (err)
break; break;
......
...@@ -1624,6 +1624,14 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, ...@@ -1624,6 +1624,14 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
if (!skb) if (!skb)
return ERR_PTR(err); return ERR_PTR(err);
/* Channel lock is released before requesting new skb and then
* reacquired thus we need to recheck channel state.
*/
if (chan->state != BT_CONNECTED) {
kfree_skb(skb);
return ERR_PTR(-ENOTCONN);
}
skb->priority = sk->sk_priority; skb->priority = sk->sk_priority;
bt_cb(skb)->l2cap.chan = chan; bt_cb(skb)->l2cap.chan = chan;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment