Skip to content

Commit ad3f798

Browse files
swkim101gregkh
authored andcommitted
Bluetooth: L2CAP: Fix div-by-zero in l2cap_le_flowctl_init()
commit a5b862c upstream. 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: 6ed58ec ("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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cfe560c commit ad3f798

File tree

7 files changed

+86
-51
lines changed

7 files changed

+86
-51
lines changed

Diff for: include/net/bluetooth/hci.h

+9
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,15 @@ struct hci_cp_le_set_event_mask {
16621662
__u8 mask[8];
16631663
} __packed;
16641664

1665+
/* BLUETOOTH CORE SPECIFICATION Version 5.4 | Vol 4, Part E
1666+
* 7.8.2 LE Read Buffer Size command
1667+
* MAX_LE_MTU is 0xffff.
1668+
* 0 is also valid. It means that no dedicated LE Buffer exists.
1669+
* It should use the HCI_Read_Buffer_Size command and mtu is shared
1670+
* between BR/EDR and LE.
1671+
*/
1672+
#define HCI_MIN_LE_MTU 0x001b
1673+
16651674
#define HCI_OP_LE_READ_BUFFER_SIZE 0x2002
16661675
struct hci_rp_le_read_buffer_size {
16671676
__u8 status;

Diff for: include/net/bluetooth/hci_core.h

+1
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@ struct hci_conn {
707707
__u16 handle;
708708
__u16 sync_handle;
709709
__u16 state;
710+
__u16 mtu;
710711
__u8 mode;
711712
__u8 type;
712713
__u8 role;

Diff for: net/bluetooth/hci_conn.c

+49-22
Original file line numberDiff line numberDiff line change
@@ -939,11 +939,37 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
939939
{
940940
struct hci_conn *conn;
941941

942+
switch (type) {
943+
case ACL_LINK:
944+
if (!hdev->acl_mtu)
945+
return ERR_PTR(-ECONNREFUSED);
946+
break;
947+
case ISO_LINK:
948+
if (hdev->iso_mtu)
949+
/* Dedicated ISO Buffer exists */
950+
break;
951+
fallthrough;
952+
case LE_LINK:
953+
if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU)
954+
return ERR_PTR(-ECONNREFUSED);
955+
if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
956+
return ERR_PTR(-ECONNREFUSED);
957+
break;
958+
case SCO_LINK:
959+
case ESCO_LINK:
960+
if (!hdev->sco_pkts)
961+
/* Controller does not support SCO or eSCO over HCI */
962+
return ERR_PTR(-ECONNREFUSED);
963+
break;
964+
default:
965+
return ERR_PTR(-ECONNREFUSED);
966+
}
967+
942968
bt_dev_dbg(hdev, "dst %pMR handle 0x%4.4x", dst, handle);
943969

944970
conn = kzalloc(sizeof(*conn), GFP_KERNEL);
945971
if (!conn)
946-
return NULL;
972+
return ERR_PTR(-ENOMEM);
947973

948974
bacpy(&conn->dst, dst);
949975
bacpy(&conn->src, &hdev->bdaddr);
@@ -974,10 +1000,12 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
9741000
switch (type) {
9751001
case ACL_LINK:
9761002
conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
1003+
conn->mtu = hdev->acl_mtu;
9771004
break;
9781005
case LE_LINK:
9791006
/* conn->src should reflect the local identity address */
9801007
hci_copy_identity_address(hdev, &conn->src, &conn->src_type);
1008+
conn->mtu = hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
9811009
break;
9821010
case ISO_LINK:
9831011
/* conn->src should reflect the local identity address */
@@ -989,16 +1017,21 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
9891017
else if (conn->role == HCI_ROLE_MASTER)
9901018
conn->cleanup = cis_cleanup;
9911019

1020+
conn->mtu = hdev->iso_mtu ? hdev->iso_mtu :
1021+
hdev->le_mtu ? hdev->le_mtu : hdev->acl_mtu;
9921022
break;
9931023
case SCO_LINK:
9941024
if (lmp_esco_capable(hdev))
9951025
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
9961026
(hdev->esco_type & EDR_ESCO_MASK);
9971027
else
9981028
conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
1029+
1030+
conn->mtu = hdev->sco_mtu;
9991031
break;
10001032
case ESCO_LINK:
10011033
conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
1034+
conn->mtu = hdev->sco_mtu;
10021035
break;
10031036
}
10041037

@@ -1041,7 +1074,7 @@ struct hci_conn *hci_conn_add_unset(struct hci_dev *hdev, int type,
10411074

10421075
handle = hci_conn_hash_alloc_unset(hdev);
10431076
if (unlikely(handle < 0))
1044-
return NULL;
1077+
return ERR_PTR(-ECONNREFUSED);
10451078

10461079
return hci_conn_add(hdev, type, dst, role, handle);
10471080
}
@@ -1384,8 +1417,8 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
13841417
bacpy(&conn->dst, dst);
13851418
} else {
13861419
conn = hci_conn_add_unset(hdev, LE_LINK, dst, role);
1387-
if (!conn)
1388-
return ERR_PTR(-ENOMEM);
1420+
if (IS_ERR(conn))
1421+
return conn;
13891422
hci_conn_hold(conn);
13901423
conn->pending_sec_level = sec_level;
13911424
}
@@ -1549,8 +1582,8 @@ static struct hci_conn *hci_add_bis(struct hci_dev *hdev, bdaddr_t *dst,
15491582
return ERR_PTR(-EADDRINUSE);
15501583

15511584
conn = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
1552-
if (!conn)
1553-
return ERR_PTR(-ENOMEM);
1585+
if (IS_ERR(conn))
1586+
return conn;
15541587

15551588
conn->state = BT_CONNECT;
15561589

@@ -1593,8 +1626,8 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst,
15931626
BT_DBG("requesting refresh of dst_addr");
15941627

15951628
conn = hci_conn_add_unset(hdev, LE_LINK, dst, HCI_ROLE_MASTER);
1596-
if (!conn)
1597-
return ERR_PTR(-ENOMEM);
1629+
if (IS_ERR(conn))
1630+
return conn;
15981631

15991632
if (hci_explicit_conn_params_set(hdev, dst, dst_type) < 0) {
16001633
hci_conn_del(conn);
@@ -1641,8 +1674,8 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
16411674
acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
16421675
if (!acl) {
16431676
acl = hci_conn_add_unset(hdev, ACL_LINK, dst, HCI_ROLE_MASTER);
1644-
if (!acl)
1645-
return ERR_PTR(-ENOMEM);
1677+
if (IS_ERR(acl))
1678+
return acl;
16461679
}
16471680

16481681
hci_conn_hold(acl);
@@ -1701,9 +1734,9 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
17011734
sco = hci_conn_hash_lookup_ba(hdev, type, dst);
17021735
if (!sco) {
17031736
sco = hci_conn_add_unset(hdev, type, dst, HCI_ROLE_MASTER);
1704-
if (!sco) {
1737+
if (IS_ERR(sco)) {
17051738
hci_conn_drop(acl);
1706-
return ERR_PTR(-ENOMEM);
1739+
return sco;
17071740
}
17081741
}
17091742

@@ -1893,8 +1926,8 @@ struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
18931926
qos->ucast.cis);
18941927
if (!cis) {
18951928
cis = hci_conn_add_unset(hdev, ISO_LINK, dst, HCI_ROLE_MASTER);
1896-
if (!cis)
1897-
return ERR_PTR(-ENOMEM);
1929+
if (IS_ERR(cis))
1930+
return cis;
18981931
cis->cleanup = cis_cleanup;
18991932
cis->dst_type = dst_type;
19001933
cis->iso_qos.ucast.cig = BT_ISO_QOS_CIG_UNSET;
@@ -2029,14 +2062,8 @@ static void hci_iso_qos_setup(struct hci_dev *hdev, struct hci_conn *conn,
20292062
struct bt_iso_io_qos *qos, __u8 phy)
20302063
{
20312064
/* Only set MTU if PHY is enabled */
2032-
if (!qos->sdu && qos->phy) {
2033-
if (hdev->iso_mtu > 0)
2034-
qos->sdu = hdev->iso_mtu;
2035-
else if (hdev->le_mtu > 0)
2036-
qos->sdu = hdev->le_mtu;
2037-
else
2038-
qos->sdu = hdev->acl_mtu;
2039-
}
2065+
if (!qos->sdu && qos->phy)
2066+
qos->sdu = conn->mtu;
20402067

20412068
/* Use the same PHY as ACL if set to any */
20422069
if (qos->phy == BT_ISO_PHY_ANY)

Diff for: net/bluetooth/hci_event.c

+20-11
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,9 @@ static u8 hci_cc_read_buffer_size(struct hci_dev *hdev, void *data,
958958
BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
959959
hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
960960

961+
if (!hdev->acl_mtu || !hdev->acl_pkts)
962+
return HCI_ERROR_INVALID_PARAMETERS;
963+
961964
return rp->status;
962965
}
963966

@@ -1267,6 +1270,9 @@ static u8 hci_cc_le_read_buffer_size(struct hci_dev *hdev, void *data,
12671270

12681271
BT_DBG("%s le mtu %d:%d", hdev->name, hdev->le_mtu, hdev->le_pkts);
12691272

1273+
if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU)
1274+
return HCI_ERROR_INVALID_PARAMETERS;
1275+
12701276
return rp->status;
12711277
}
12721278

@@ -2351,8 +2357,8 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
23512357
if (!conn) {
23522358
conn = hci_conn_add_unset(hdev, ACL_LINK, &cp->bdaddr,
23532359
HCI_ROLE_MASTER);
2354-
if (!conn)
2355-
bt_dev_err(hdev, "no memory for new connection");
2360+
if (IS_ERR(conn))
2361+
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
23562362
}
23572363
}
23582364

@@ -3165,8 +3171,8 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data,
31653171
BDADDR_BREDR)) {
31663172
conn = hci_conn_add_unset(hdev, ev->link_type,
31673173
&ev->bdaddr, HCI_ROLE_SLAVE);
3168-
if (!conn) {
3169-
bt_dev_err(hdev, "no memory for new conn");
3174+
if (IS_ERR(conn)) {
3175+
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
31703176
goto unlock;
31713177
}
31723178
} else {
@@ -3356,8 +3362,8 @@ static void hci_conn_request_evt(struct hci_dev *hdev, void *data,
33563362
if (!conn) {
33573363
conn = hci_conn_add_unset(hdev, ev->link_type, &ev->bdaddr,
33583364
HCI_ROLE_SLAVE);
3359-
if (!conn) {
3360-
bt_dev_err(hdev, "no memory for new connection");
3365+
if (IS_ERR(conn)) {
3366+
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
33613367
goto unlock;
33623368
}
33633369
}
@@ -3834,6 +3840,9 @@ static u8 hci_cc_le_read_buffer_size_v2(struct hci_dev *hdev, void *data,
38343840
BT_DBG("%s acl mtu %d:%d iso mtu %d:%d", hdev->name, hdev->acl_mtu,
38353841
hdev->acl_pkts, hdev->iso_mtu, hdev->iso_pkts);
38363842

3843+
if (hdev->le_mtu && hdev->le_mtu < HCI_MIN_LE_MTU)
3844+
return HCI_ERROR_INVALID_PARAMETERS;
3845+
38373846
return rp->status;
38383847
}
38393848

@@ -5925,8 +5934,8 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status,
59255934
goto unlock;
59265935

59275936
conn = hci_conn_add_unset(hdev, LE_LINK, bdaddr, role);
5928-
if (!conn) {
5929-
bt_dev_err(hdev, "no memory for new connection");
5937+
if (IS_ERR(conn)) {
5938+
bt_dev_err(hdev, "connection err: %ld", PTR_ERR(conn));
59305939
goto unlock;
59315940
}
59325941

@@ -7051,7 +7060,7 @@ static void hci_le_cis_req_evt(struct hci_dev *hdev, void *data,
70517060
if (!cis) {
70527061
cis = hci_conn_add(hdev, ISO_LINK, &acl->dst, HCI_ROLE_SLAVE,
70537062
cis_handle);
7054-
if (!cis) {
7063+
if (IS_ERR(cis)) {
70557064
hci_le_reject_cis(hdev, ev->cis_handle);
70567065
goto unlock;
70577066
}
@@ -7170,7 +7179,7 @@ static void hci_le_big_sync_established_evt(struct hci_dev *hdev, void *data,
71707179
if (!bis) {
71717180
bis = hci_conn_add(hdev, ISO_LINK, BDADDR_ANY,
71727181
HCI_ROLE_SLAVE, handle);
7173-
if (!bis)
7182+
if (IS_ERR(bis))
71747183
continue;
71757184
}
71767185

@@ -7242,7 +7251,7 @@ static void hci_le_big_info_adv_report_evt(struct hci_dev *hdev, void *data,
72427251
pa_sync = hci_conn_add_unset(hdev, ISO_LINK, BDADDR_ANY,
72437252
HCI_ROLE_SLAVE);
72447253

7245-
if (!pa_sync)
7254+
if (IS_ERR(pa_sync))
72467255
goto unlock;
72477256

72487257
pa_sync->sync_handle = le16_to_cpu(ev->sync_handle);

Diff for: net/bluetooth/iso.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1135,7 +1135,7 @@ static int iso_sock_sendmsg(struct socket *sock, struct msghdr *msg,
11351135
return -ENOTCONN;
11361136
}
11371137

1138-
mtu = iso_pi(sk)->conn->hcon->hdev->iso_mtu;
1138+
mtu = iso_pi(sk)->conn->hcon->mtu;
11391139

11401140
release_sock(sk);
11411141

Diff for: net/bluetooth/l2cap_core.c

+3-14
Original file line numberDiff line numberDiff line change
@@ -6241,7 +6241,7 @@ static int l2cap_finish_move(struct l2cap_chan *chan)
62416241
BT_DBG("chan %p", chan);
62426242

62436243
chan->rx_state = L2CAP_RX_STATE_RECV;
6244-
chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
6244+
chan->conn->mtu = chan->conn->hcon->mtu;
62456245

62466246
return l2cap_resegment(chan);
62476247
}
@@ -6308,7 +6308,7 @@ static int l2cap_rx_state_wait_f(struct l2cap_chan *chan,
63086308
*/
63096309
chan->next_tx_seq = control->reqseq;
63106310
chan->unacked_frames = 0;
6311-
chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
6311+
chan->conn->mtu = chan->conn->hcon->mtu;
63126312

63136313
err = l2cap_resegment(chan);
63146314

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

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

6851-
switch (hcon->type) {
6852-
case LE_LINK:
6853-
if (hcon->hdev->le_mtu) {
6854-
conn->mtu = hcon->hdev->le_mtu;
6855-
break;
6856-
}
6857-
fallthrough;
6858-
default:
6859-
conn->mtu = hcon->hdev->acl_mtu;
6860-
break;
6861-
}
6862-
6851+
conn->mtu = hcon->mtu;
68636852
conn->feat_mask = 0;
68646853

68656854
conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS;

Diff for: net/bluetooth/sco.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ static void sco_sock_clear_timer(struct sock *sk)
126126
/* ---- SCO connections ---- */
127127
static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
128128
{
129-
struct hci_dev *hdev = hcon->hdev;
130129
struct sco_conn *conn = hcon->sco_data;
131130

132131
if (conn) {
@@ -144,9 +143,10 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
144143

145144
hcon->sco_data = conn;
146145
conn->hcon = hcon;
146+
conn->mtu = hcon->mtu;
147147

148-
if (hdev->sco_mtu > 0)
149-
conn->mtu = hdev->sco_mtu;
148+
if (hcon->mtu > 0)
149+
conn->mtu = hcon->mtu;
150150
else
151151
conn->mtu = 60;
152152

0 commit comments

Comments
 (0)