Skip to content

Commit af3d5d1

Browse files
holtmannJohan Hedberg
authored andcommitted
Bluetooth: Check L2CAP option sizes returned from l2cap_get_conf_opt
When doing option parsing for standard type values of 1, 2 or 4 octets, the value is converted directly into a variable instead of a pointer. To avoid being tricked into being a pointer, check that for these option types that sizes actually match. In L2CAP every option is fixed size and thus it is prudent anyway to ensure that the remote side sends us the right option size along with option paramters. If the option size is not matching the option type, then that option is silently ignored. It is a protocol violation and instead of trying to give the remote attacker any further hints just pretend that option is not present and proceed with the default values. Implementation following the specification and its qualification procedures will always use the correct size and thus not being impacted here. To keep the code readable and consistent accross all options, a few cosmetic changes were also required. Signed-off-by: Marcel Holtmann <[email protected]> Reviewed-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Johan Hedberg <[email protected]>
1 parent 099791d commit af3d5d1

File tree

1 file changed

+46
-31
lines changed

1 file changed

+46
-31
lines changed

net/bluetooth/l2cap_core.c

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3343,37 +3343,45 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
33433343

33443344
switch (type) {
33453345
case L2CAP_CONF_MTU:
3346+
if (olen != 2)
3347+
break;
33463348
mtu = val;
33473349
break;
33483350

33493351
case L2CAP_CONF_FLUSH_TO:
3352+
if (olen != 2)
3353+
break;
33503354
chan->flush_to = val;
33513355
break;
33523356

33533357
case L2CAP_CONF_QOS:
33543358
break;
33553359

33563360
case L2CAP_CONF_RFC:
3357-
if (olen == sizeof(rfc))
3358-
memcpy(&rfc, (void *) val, olen);
3361+
if (olen != sizeof(rfc))
3362+
break;
3363+
memcpy(&rfc, (void *) val, olen);
33593364
break;
33603365

33613366
case L2CAP_CONF_FCS:
3367+
if (olen != 1)
3368+
break;
33623369
if (val == L2CAP_FCS_NONE)
33633370
set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
33643371
break;
33653372

33663373
case L2CAP_CONF_EFS:
3367-
if (olen == sizeof(efs)) {
3368-
remote_efs = 1;
3369-
memcpy(&efs, (void *) val, olen);
3370-
}
3374+
if (olen != sizeof(efs))
3375+
break;
3376+
remote_efs = 1;
3377+
memcpy(&efs, (void *) val, olen);
33713378
break;
33723379

33733380
case L2CAP_CONF_EWS:
3381+
if (olen != 2)
3382+
break;
33743383
if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
33753384
return -ECONNREFUSED;
3376-
33773385
set_bit(FLAG_EXT_CTRL, &chan->flags);
33783386
set_bit(CONF_EWS_RECV, &chan->conf_state);
33793387
chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
@@ -3383,7 +3391,6 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data
33833391
default:
33843392
if (hint)
33853393
break;
3386-
33873394
result = L2CAP_CONF_UNKNOWN;
33883395
*((u8 *) ptr++) = type;
33893396
break;
@@ -3551,55 +3558,60 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
35513558

35523559
switch (type) {
35533560
case L2CAP_CONF_MTU:
3561+
if (olen != 2)
3562+
break;
35543563
if (val < L2CAP_DEFAULT_MIN_MTU) {
35553564
*result = L2CAP_CONF_UNACCEPT;
35563565
chan->imtu = L2CAP_DEFAULT_MIN_MTU;
35573566
} else
35583567
chan->imtu = val;
3559-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu, endptr - ptr);
3568+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu,
3569+
endptr - ptr);
35603570
break;
35613571

35623572
case L2CAP_CONF_FLUSH_TO:
3573+
if (olen != 2)
3574+
break;
35633575
chan->flush_to = val;
3564-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
3565-
2, chan->flush_to, endptr - ptr);
3576+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2,
3577+
chan->flush_to, endptr - ptr);
35663578
break;
35673579

35683580
case L2CAP_CONF_RFC:
3569-
if (olen == sizeof(rfc))
3570-
memcpy(&rfc, (void *)val, olen);
3571-
3581+
if (olen != sizeof(rfc))
3582+
break;
3583+
memcpy(&rfc, (void *)val, olen);
35723584
if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
35733585
rfc.mode != chan->mode)
35743586
return -ECONNREFUSED;
3575-
35763587
chan->fcs = 0;
3577-
3578-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
3579-
sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
3588+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
3589+
(unsigned long) &rfc, endptr - ptr);
35803590
break;
35813591

35823592
case L2CAP_CONF_EWS:
3593+
if (olen != 2)
3594+
break;
35833595
chan->ack_win = min_t(u16, val, chan->ack_win);
35843596
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
35853597
chan->tx_win, endptr - ptr);
35863598
break;
35873599

35883600
case L2CAP_CONF_EFS:
3589-
if (olen == sizeof(efs)) {
3590-
memcpy(&efs, (void *)val, olen);
3591-
3592-
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
3593-
efs.stype != L2CAP_SERV_NOTRAFIC &&
3594-
efs.stype != chan->local_stype)
3595-
return -ECONNREFUSED;
3596-
3597-
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
3598-
(unsigned long) &efs, endptr - ptr);
3599-
}
3601+
if (olen != sizeof(efs))
3602+
break;
3603+
memcpy(&efs, (void *)val, olen);
3604+
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
3605+
efs.stype != L2CAP_SERV_NOTRAFIC &&
3606+
efs.stype != chan->local_stype)
3607+
return -ECONNREFUSED;
3608+
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
3609+
(unsigned long) &efs, endptr - ptr);
36003610
break;
36013611

36023612
case L2CAP_CONF_FCS:
3613+
if (olen != 1)
3614+
break;
36033615
if (*result == L2CAP_CONF_PENDING)
36043616
if (val == L2CAP_FCS_NONE)
36053617
set_bit(CONF_RECV_NO_FCS,
@@ -3731,10 +3743,13 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
37313743

37323744
switch (type) {
37333745
case L2CAP_CONF_RFC:
3734-
if (olen == sizeof(rfc))
3735-
memcpy(&rfc, (void *)val, olen);
3746+
if (olen != sizeof(rfc))
3747+
break;
3748+
memcpy(&rfc, (void *)val, olen);
37363749
break;
37373750
case L2CAP_CONF_EWS:
3751+
if (olen != 2)
3752+
break;
37383753
txwin_ext = val;
37393754
break;
37403755
}

0 commit comments

Comments
 (0)