From: Sungwoo Kim iam@sung-woo.kim
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/?i...
--------------------------------
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: 6ed58ec520ad ("Bluetooth: Use LE buffers for LE traffic") Suggested-by: Luiz Augusto von Dentz luiz.dentz@gmail.com Signed-off-by: Sungwoo Kim iam@sung-woo.kim Signed-off-by: Luiz 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 [The conflict occurs because the commit eca0ae4aea66("Bluetooth: Add initial implementation of BIS connections") and 26afbd826ee3("Bluetooth: Add initial implementation of CIS connections") and 181a42edddf5(" Bluetooth: Make handle of hci_conn be unique") and c8992cffbe74(" Bluetooth: hci_event: Use of a function table to handle Command Complete") and e7b02296fb40 ("Bluetooth: Remove BT_HS") 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: Zhengchao Shao shaozhengchao@huawei.com --- include/net/bluetooth/hci.h | 9 +++++++++ include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 26 ++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 8 ++++++++ net/bluetooth/l2cap_core.c | 17 +++-------------- net/bluetooth/sco.c | 6 +++--- 6 files changed, 50 insertions(+), 17 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ede7a153c69a..e6dfbeb4f663 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -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; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 11a92bb4d7a9..5d8b6bd87495 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -602,6 +602,7 @@ struct hci_conn { __u8 resp_addr_type; __u16 handle; __u16 state; + __u16 mtu; __u8 mode; __u8 type; __u8 role; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 140d9764c77e..9478e63f10ef 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -522,6 +522,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); @@ -555,10 +576,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)) @@ -566,9 +589,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; }
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 954b29605c94..ea83c75da095 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -729,6 +729,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); @@ -1018,6 +1022,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;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 1677cbb77578..c3b6a416119e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7204,7 +7204,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); } @@ -7275,7 +7275,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);
@@ -7826,18 +7826,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; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index f9a2993fd452..1e5daa03155f 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -127,7 +127,6 @@ static void sco_sock_clear_timer(struct sock *sk) /* ---- SCO connections ---- */ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) { - struct hci_dev *hdev = hcon->hdev; struct sco_conn *conn = hcon->sco_data;
if (conn) @@ -142,9 +141,10 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
hcon->sco_data = conn; conn->hcon = hcon; + conn->mtu = hcon->mtu;
- if (hdev->sco_mtu > 0) - conn->mtu = hdev->sco_mtu; + if (hcon->mtu > 0) + conn->mtu = hcon->mtu; else conn->mtu = 60;