Skip to content

Commit 457a23c

Browse files
Lyle_Linalex3788
authored andcommitted
[SECURITY-PATCH] Bluetooth: Properly check L2CAP config option output buffer length
Validate the output buffer length for L2CAP config requests and responses to avoid overflowing the stack buffer used for building the option blocks. Change-Id: I8048b8beffa6dc99069ea1e3ec4b38bd382fd03b Reviewed-on: https://tp-biosrd-v02/gerrit/80835 Reviewed-by: Alex Cheng(鄭富元) <[email protected]> Tested-by: Alex Cheng(鄭富元) <[email protected]>
1 parent 2577a6e commit 457a23c

File tree

1 file changed

+43
-37
lines changed

1 file changed

+43
-37
lines changed

net/bluetooth/l2cap_core.c

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
5757
u8 code, u8 ident, u16 dlen, void *data);
5858
static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
5959
void *data);
60-
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
60+
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size);
6161
static void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
6262

6363
static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
@@ -1462,7 +1462,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
14621462

14631463
set_bit(CONF_REQ_SENT, &chan->conf_state);
14641464
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
1465-
l2cap_build_conf_req(chan, buf), buf);
1465+
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
14661466
chan->num_conf_req++;
14671467
}
14681468

@@ -2966,12 +2966,15 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
29662966
return len;
29672967
}
29682968

2969-
static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
2969+
static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val, size_t size)
29702970
{
29712971
struct l2cap_conf_opt *opt = *ptr;
29722972

29732973
BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val);
29742974

2975+
if (size < L2CAP_CONF_OPT_SIZE + len)
2976+
return;
2977+
29752978
opt->type = type;
29762979
opt->len = len;
29772980

@@ -2996,7 +2999,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
29962999
*ptr += L2CAP_CONF_OPT_SIZE + len;
29973000
}
29983001

2999-
static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
3002+
static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan, size_t size)
30003003
{
30013004
struct l2cap_conf_efs efs;
30023005

@@ -3024,7 +3027,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
30243027
}
30253028

30263029
l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
3027-
(unsigned long) &efs);
3030+
(unsigned long) &efs, size);
30283031
}
30293032

30303033
static void l2cap_ack_timeout(struct work_struct *work)
@@ -3170,11 +3173,12 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
31703173
chan->ack_win = chan->tx_win;
31713174
}
31723175

3173-
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
3176+
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
31743177
{
31753178
struct l2cap_conf_req *req = data;
31763179
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
31773180
void *ptr = req->data;
3181+
void *endptr = data + data_size;
31783182
u16 size;
31793183

31803184
BT_DBG("chan %p", chan);
@@ -3199,7 +3203,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
31993203

32003204
done:
32013205
if (chan->imtu != L2CAP_DEFAULT_MTU)
3202-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
3206+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
32033207

32043208
switch (chan->mode) {
32053209
case L2CAP_MODE_BASIC:
@@ -3218,7 +3222,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
32183222
rfc.max_pdu_size = 0;
32193223

32203224
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
3221-
(unsigned long) &rfc);
3225+
(unsigned long) &rfc, endptr - ptr);
32223226
break;
32233227

32243228
case L2CAP_MODE_ERTM:
@@ -3238,21 +3242,21 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
32383242
L2CAP_DEFAULT_TX_WINDOW);
32393243

32403244
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
3241-
(unsigned long) &rfc);
3245+
(unsigned long) &rfc, endptr - ptr);
32423246

32433247
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
3244-
l2cap_add_opt_efs(&ptr, chan);
3248+
l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
32453249

32463250
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
32473251
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
3248-
chan->tx_win);
3252+
chan->tx_win, endptr - ptr);
32493253

32503254
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
32513255
if (chan->fcs == L2CAP_FCS_NONE ||
32523256
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
32533257
chan->fcs = L2CAP_FCS_NONE;
32543258
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
3255-
chan->fcs);
3259+
chan->fcs, endptr - ptr);
32563260
}
32573261
break;
32583262

@@ -3270,17 +3274,17 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
32703274
rfc.max_pdu_size = cpu_to_le16(size);
32713275

32723276
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
3273-
(unsigned long) &rfc);
3277+
(unsigned long) &rfc, endptr - ptr);
32743278

32753279
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
3276-
l2cap_add_opt_efs(&ptr, chan);
3280+
l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
32773281

32783282
if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
32793283
if (chan->fcs == L2CAP_FCS_NONE ||
32803284
test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
32813285
chan->fcs = L2CAP_FCS_NONE;
32823286
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
3283-
chan->fcs);
3287+
chan->fcs, endptr - ptr);
32843288
}
32853289
break;
32863290
}
@@ -3291,10 +3295,11 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
32913295
return ptr - data;
32923296
}
32933297

3294-
static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
3298+
static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
32953299
{
32963300
struct l2cap_conf_rsp *rsp = data;
32973301
void *ptr = rsp->data;
3302+
void *endptr = data + data_size;
32983303
void *req = chan->conf_req;
32993304
int len = chan->conf_len;
33003305
int type, hint, olen;
@@ -3396,7 +3401,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
33963401
return -ECONNREFUSED;
33973402

33983403
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
3399-
(unsigned long) &rfc);
3404+
(unsigned long) &rfc, endptr - ptr);
34003405
}
34013406

34023407
if (result == L2CAP_CONF_SUCCESS) {
@@ -3409,7 +3414,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
34093414
chan->omtu = mtu;
34103415
set_bit(CONF_MTU_DONE, &chan->conf_state);
34113416
}
3412-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
3417+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu, endptr - ptr);
34133418

34143419
if (remote_efs) {
34153420
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
@@ -3423,7 +3428,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
34233428

34243429
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
34253430
sizeof(efs),
3426-
(unsigned long) &efs);
3431+
(unsigned long) &efs, endptr - ptr);
34273432
} else {
34283433
/* Send PENDING Conf Rsp */
34293434
result = L2CAP_CONF_PENDING;
@@ -3456,7 +3461,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
34563461
set_bit(CONF_MODE_DONE, &chan->conf_state);
34573462

34583463
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
3459-
sizeof(rfc), (unsigned long) &rfc);
3464+
sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
34603465

34613466
if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
34623467
chan->remote_id = efs.id;
@@ -3470,7 +3475,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
34703475
le32_to_cpu(efs.sdu_itime);
34713476
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
34723477
sizeof(efs),
3473-
(unsigned long) &efs);
3478+
(unsigned long) &efs, endptr - ptr);
34743479
}
34753480
break;
34763481

@@ -3484,7 +3489,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
34843489
set_bit(CONF_MODE_DONE, &chan->conf_state);
34853490

34863491
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
3487-
(unsigned long) &rfc);
3492+
(unsigned long) &rfc, endptr - ptr);
34883493

34893494
break;
34903495

@@ -3506,10 +3511,11 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
35063511
}
35073512

35083513
static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
3509-
void *data, u16 *result)
3514+
void *data, size_t size, u16 *result)
35103515
{
35113516
struct l2cap_conf_req *req = data;
35123517
void *ptr = req->data;
3518+
void *endptr = data + size;
35133519
int type, olen;
35143520
unsigned long val;
35153521
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
@@ -3527,13 +3533,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
35273533
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
35283534
} else
35293535
chan->imtu = val;
3530-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
3536+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
35313537
break;
35323538

35333539
case L2CAP_CONF_FLUSH_TO:
35343540
chan->flush_to = val;
35353541
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
3536-
2, chan->flush_to);
3542+
2, chan->flush_to, endptr - ptr);
35373543
break;
35383544

35393545
case L2CAP_CONF_RFC:
@@ -3547,13 +3553,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
35473553
chan->fcs = 0;
35483554

35493555
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
3550-
sizeof(rfc), (unsigned long) &rfc);
3556+
sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
35513557
break;
35523558

35533559
case L2CAP_CONF_EWS:
35543560
chan->ack_win = min_t(u16, val, chan->ack_win);
35553561
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
3556-
chan->tx_win);
3562+
chan->tx_win, endptr - ptr);
35573563
break;
35583564

35593565
case L2CAP_CONF_EFS:
@@ -3566,7 +3572,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
35663572
return -ECONNREFUSED;
35673573

35683574
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
3569-
(unsigned long) &efs);
3575+
(unsigned long) &efs, endptr - ptr);
35703576
break;
35713577

35723578
case L2CAP_CONF_FCS:
@@ -3671,7 +3677,7 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
36713677
return;
36723678

36733679
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
3674-
l2cap_build_conf_req(chan, buf), buf);
3680+
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
36753681
chan->num_conf_req++;
36763682
}
36773683

@@ -3879,7 +3885,7 @@ static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
38793885
u8 buf[128];
38803886
set_bit(CONF_REQ_SENT, &chan->conf_state);
38813887
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
3882-
l2cap_build_conf_req(chan, buf), buf);
3888+
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
38833889
chan->num_conf_req++;
38843890
}
38853891

@@ -3957,7 +3963,7 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
39573963
break;
39583964

39593965
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
3960-
l2cap_build_conf_req(chan, req), req);
3966+
l2cap_build_conf_req(chan, req, sizeof(req)), req);
39613967
chan->num_conf_req++;
39623968
break;
39633969

@@ -4069,7 +4075,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
40694075
}
40704076

40714077
/* Complete config. */
4072-
len = l2cap_parse_conf_req(chan, rsp);
4078+
len = l2cap_parse_conf_req(chan, rsp, sizeof(rsp));
40734079
if (len < 0) {
40744080
l2cap_send_disconn_req(chan, ECONNRESET);
40754081
goto unlock;
@@ -4103,7 +4109,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
41034109
if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
41044110
u8 buf[64];
41054111
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
4106-
l2cap_build_conf_req(chan, buf), buf);
4112+
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
41074113
chan->num_conf_req++;
41084114
}
41094115

@@ -4163,7 +4169,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
41634169
char buf[64];
41644170

41654171
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
4166-
buf, &result);
4172+
buf, sizeof(buf), &result);
41674173
if (len < 0) {
41684174
l2cap_send_disconn_req(chan, ECONNRESET);
41694175
goto done;
@@ -4193,7 +4199,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
41934199
/* throw out any old stored conf requests */
41944200
result = L2CAP_CONF_SUCCESS;
41954201
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
4196-
req, &result);
4202+
req, sizeof(req), &result);
41974203
if (len < 0) {
41984204
l2cap_send_disconn_req(chan, ECONNRESET);
41994205
goto done;
@@ -4770,7 +4776,7 @@ static void l2cap_do_create(struct l2cap_chan *chan, int result,
47704776
set_bit(CONF_REQ_SENT, &chan->conf_state);
47714777
l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
47724778
L2CAP_CONF_REQ,
4773-
l2cap_build_conf_req(chan, buf), buf);
4779+
l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
47744780
chan->num_conf_req++;
47754781
}
47764782
}
@@ -7442,7 +7448,7 @@ static void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
74427448
set_bit(CONF_REQ_SENT, &chan->conf_state);
74437449
l2cap_send_cmd(conn, l2cap_get_ident(conn),
74447450
L2CAP_CONF_REQ,
7445-
l2cap_build_conf_req(chan, buf),
7451+
l2cap_build_conf_req(chan, buf, sizeof(buf)),
74467452
buf);
74477453
chan->num_conf_req++;
74487454
}

0 commit comments

Comments
 (0)