Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60aaccf1 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Greg Kroah-Hartman
Browse files

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: 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>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent d19bd485
Loading
Loading
Loading
Loading
+0 −24
Original line number Diff line number Diff line
@@ -2526,14 +2526,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
		if (IS_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);
		return len;
	}
@@ -2577,14 +2569,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
		if (IS_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);
		err = len;
		break;
@@ -2605,14 +2589,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t 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)
			break;

+8 −0
Original line number Diff line number Diff line
@@ -1433,6 +1433,14 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
	if (!skb)
		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;

	bt_cb(skb)->l2cap.chan = chan;