Commit c0fd4f88 authored by Sungwoo Kim's avatar Sungwoo Kim Committed by Zhengchao Shao
Browse files

Bluetooth: L2CAP: Fix div-by-zero in l2cap_le_flowctl_init()

mainline inclusion
from mainline-v6.10-rc1
commit a5b862c6a221459d54e494e88965b48dcfa6cc44
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IA3COJ
CVE: CVE-2024-36968

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5b862c6a221459d54e494e88965b48dcfa6cc44



--------------------------------

l2cap_le_flowctl_init() can cause both div-by-zero and an integer
overflow since hdev->le_mtu may not fall in the valid range.

Move MTU from hci_dev to hci_conn to validate MTU and stop the connection
process earlier if MTU is invalid.
Also, add a missing validation in read_buffer_size() and make it return
an error value if the validation fails.
Now hci_conn_add() returns ERR_PTR() as it can fail due to the both a
kzalloc failure and invalid MTU value.

divide error: 0000 [#1] PREEMPT SMP KASAN NOPTI
CPU: 0 PID: 67 Comm: kworker/u5:0 Tainted: G        W          6.9.0-rc5+ #20
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
Workqueue: hci0 hci_rx_work
RIP: 0010:l2cap_le_flowctl_init+0x19e/0x3f0 net/bluetooth/l2cap_core.c:547
Code: e8 17 17 0c 00 66 41 89 9f 84 00 00 00 bf 01 00 00 00 41 b8 02 00 00 00 4c
89 fe 4c 89 e2 89 d9 e8 27 17 0c 00 44 89 f0 31 d2 <66> f7 f3 89 c3 ff c3 4d 8d
b7 88 00 00 00 4c 89 f0 48 c1 e8 03 42
RSP: 0018:ffff88810bc0f858 EFLAGS: 00010246
RAX: 00000000000002a0 RBX: 0000000000000000 RCX: dffffc0000000000
RDX: 0000000000000000 RSI: ffff88810bc0f7c0 RDI: ffffc90002dcb66f
RBP: ffff88810bc0f880 R08: aa69db2dda70ff01 R09: 0000ffaaaaaaaaaa
R10: 0084000000ffaaaa R11: 0000000000000000 R12: ffff88810d65a084
R13: dffffc0000000000 R14: 00000000000002a0 R15: ffff88810d65a000
FS:  0000000000000000(0000) GS:ffff88811ac00000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000020000100 CR3: 0000000103268003 CR4: 0000000000770ef0
PKRU: 55555554
Call Trace:
 <TASK>
 l2cap_le_connect_req net/bluetooth/l2cap_core.c:4902 [inline]
 l2cap_le_sig_cmd net/bluetooth/l2cap_core.c:5420 [inline]
 l2cap_le_sig_channel net/bluetooth/l2cap_core.c:5486 [inline]
 l2cap_recv_frame+0xe59d/0x11710 net/bluetooth/l2cap_core.c:6809
 l2cap_recv_acldata+0x544/0x10a0 net/bluetooth/l2cap_core.c:7506
 hci_acldata_packet net/bluetooth/hci_core.c:3939 [inline]
 hci_rx_work+0x5e5/0xb20 net/bluetooth/hci_core.c:4176
 process_one_work kernel/workqueue.c:3254 [inline]
 process_scheduled_works+0x90f/0x1530 kernel/workqueue.c:3335
 worker_thread+0x926/0xe70 kernel/workqueue.c:3416
 kthread+0x2e3/0x380 kernel/kthread.c:388
 ret_from_fork+0x5c/0x90 arch/x86/kernel/process.c:147
 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:244
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---

Fixes: 6ed58ec5 ("Bluetooth: Use LE buffers for LE traffic")
Suggested-by: default avatarLuiz Augusto von Dentz <luiz.dentz@gmail.com>
Signed-off-by: default avatarSungwoo Kim <iam@sung-woo.kim>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>

Conflicts:
	include/net/bluetooth/hci_core.h
	net/bluetooth/hci_conn.c
	net/bluetooth/hci_event.c
	net/bluetooth/l2cap_core.c
	net/bluetooth/sco.c
	net/bluetooth/iso.c
[The conflict occurs because the commit eca0ae4a("Bluetooth: Add
initial implementation of BIS connections") and 26afbd82("Bluetooth:
Add initial implementation of CIS connections") and 181a42edddf5("
Bluetooth: Make handle of hci_conn be unique") and c8992cff("
Bluetooth: hci_event: Use of a function table to handle Command
Complete") and e7b02296fb40 ("Bluetooth: Remove BT_HS") and ccf74f23
("Bluetooth: Add BTPROTO_ISO socket type") are not merged.
In the hci_conn_add function, if the MTU is abnormal, NULL is returned.
No adaptation is required in subsequent interfaces]
Signed-off-by: default avatarZhengchao Shao <shaozhengchao@huawei.com>
parent 50f1377f
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -1430,6 +1430,15 @@ struct hci_cp_le_set_event_mask {
	__u8     mask[8];
} __packed;

/* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E
 * 7.8.2 LE Read Buffer Size command
 * MAX_LE_MTU is 0xffff.
 * 0 is also valid. It means that no dedicated LE Buffer exists.
 * It should use the HCI_Read_Buffer_Size command and mtu is shared
 * between BR/EDR and LE.
 */
#define HCI_MIN_LE_MTU 0x001b

#define HCI_OP_LE_READ_BUFFER_SIZE	0x2002
struct hci_rp_le_read_buffer_size {
	__u8     status;
+1 −0
Original line number Diff line number Diff line
@@ -607,6 +607,7 @@ struct hci_conn {
	__u8		resp_addr_type;
	__u16		handle;
	__u16		state;
	__u16		mtu;
	__u8		mode;
	__u8		type;
	__u8		role;
+26 −0
Original line number Diff line number Diff line
@@ -520,6 +520,27 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
{
	struct hci_conn *conn;

	switch (type) {
	case ACL_LINK:
		if (!hdev->acl_mtu)
			return NULL;
		break;
	case LE_LINK:
		if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU)
			return NULL;
		if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
			return NULL;
		break;
	case SCO_LINK:
	case ESCO_LINK:
		if (!hdev->sco_pkts)
			/* Controller does not support SCO or eSCO over HCI */
			return NULL;
		break;
	default:
		return NULL;
	}

	BT_DBG("%s dst %pMR", hdev->name, dst);

	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
@@ -553,10 +574,12 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
	switch (type) {
	case ACL_LINK:
		conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
		conn->mtu = hdev->acl_mtu;
		break;
	case LE_LINK:
		/* conn->src should reflect the local identity address */
		hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
		conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
		break;
	case SCO_LINK:
		if (lmp_esco_capable(hdev))
@@ -564,9 +587,12 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
					(hdev->esco_type & EDR_ESCO_MASK);
		else
			conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;

		conn->mtu = hdev->sco_mtu;
		break;
	case ESCO_LINK:
		conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
		conn->mtu = hdev->sco_mtu;
		break;
	}

+8 −0
Original line number Diff line number Diff line
@@ -731,6 +731,10 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
	if (rp->status)
		return;

	if (!__le16_to_cpu(rp->acl_mtu) ||
	    !__le16_to_cpu(rp->acl_max_pkt))
		return;

	hdev->acl_mtu  = __le16_to_cpu(rp->acl_mtu);
	hdev->sco_mtu  = rp->sco_mtu;
	hdev->acl_pkts = __le16_to_cpu(rp->acl_max_pkt);
@@ -1020,6 +1024,10 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
	if (rp->status)
		return;

	if (__le16_to_cpu(rp->le_mtu) &&
	    __le16_to_cpu(rp->le_mtu) < HCI_MIN_LE_MTU)
		return;

	hdev->le_mtu = __le16_to_cpu(rp->le_mtu);
	hdev->le_pkts = rp->le_max_pkt;

+3 −14
Original line number Diff line number Diff line
@@ -7241,7 +7241,7 @@ static int l2cap_finish_move(struct l2cap_chan *chan)
	if (chan->hs_hcon)
		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu;
	else
		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
		chan->conn->mtu = chan->conn->hcon->mtu;

	return l2cap_resegment(chan);
}
@@ -7312,7 +7312,7 @@ static int l2cap_rx_state_wait_f(struct l2cap_chan *chan,
	if (chan->hs_hcon)
		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu;
	else
		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
		chan->conn->mtu = chan->conn->hcon->mtu;

	err = l2cap_resegment(chan);

@@ -7863,18 +7863,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)

	BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);

	switch (hcon->type) {
	case LE_LINK:
		if (hcon->hdev->le_mtu) {
			conn->mtu = hcon->hdev->le_mtu;
			break;
		}
		fallthrough;
	default:
		conn->mtu = hcon->hdev->acl_mtu;
		break;
	}

	conn->mtu = hcon->mtu;
	conn->feat_mask = 0;

	conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS;
Loading