Bluetooth: L2CAP: Fix potential user-after-free
[ Upstream commit df5703348813235874d851934e957c3723d71644 ]
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: a6a5568c03
("Bluetooth: Lock the L2CAP channel when sending")
Reported-by: Alexander Coffin <alex.coffin@matician.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
4f4c970a05
commit
b8ed41cc04
@@ -2679,14 +2679,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;
|
||||||
}
|
}
|
||||||
@@ -2731,14 +2723,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;
|
||||||
@@ -2759,14 +2743,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;
|
||||||
|
|
||||||
|
@@ -1623,6 +1623,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;
|
||||||
|
Reference in New Issue
Block a user