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

Commit eb622495 authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann
Browse files

Bluetooth: Fix ATT socket backwards compatibility with user space



Old user space versions bind the Attribute Protocol socket to
BDADDR_BREDR when they should be using BDADDR_LE_PUBLIC or
BDADDR_LE_RANDOM. The kernel recently introduced stricter checks on the
socket parameters but we need to punch this hole for old user space
versions to keep them working.

Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 2bfa3531
Loading
Loading
Loading
Loading
+25 −2
Original line number Diff line number Diff line
@@ -159,9 +159,32 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
	if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
		return -EINVAL;

	if (chan->src_type == BDADDR_BREDR && la.l2_bdaddr_type != BDADDR_BREDR)
	/* Check that the socket wasn't bound to something that
	 * conflicts with the address given to connect(). If chan->src
	 * is BDADDR_ANY it means bind() was never used, in which case
	 * chan->src_type and la.l2_bdaddr_type do not need to match.
	 */
	if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
	    bdaddr_type_is_le(la.l2_bdaddr_type)) {
		/* Old user space versions will try to incorrectly bind
		 * the ATT socket using BDADDR_BREDR. We need to accept
		 * this and fix up the source address type only when
		 * both the source CID and destination CID indicate
		 * ATT. Anything else is an invalid combination.
		 */
		if (chan->scid != L2CAP_CID_ATT ||
		    la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
			return -EINVAL;

		/* We don't have the hdev available here to make a
		 * better decision on random vs public, but since all
		 * user space versions that exhibit this issue anyway do
		 * not support random local addresses assuming public
		 * here is good enough.
		 */
		chan->src_type = BDADDR_LE_PUBLIC;
	}

	if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR)
		return -EINVAL;