Bluetooth: L2CAP: Fix use of uninitializer pointer

l2cap_br_conn_req_reply expects valid bt_l2cap_chan pointer but this
is achieved only on accept() callback. Use l2cap_br_send_conn_rsp
instead for rejecting cases where no channel was accepted. This also
makes success path being 'primary' function path ie erros all always
handled inside if() statements.

Jira: ZEP-1405

Change-Id: I890b4fcf029afce65eba4f2ebae0b1094feb007f
Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
This commit is contained in:
Szymon Janc 2016-12-22 19:48:08 +01:00 committed by Johan Hedberg
commit ba2adb70b2

View file

@ -747,7 +747,7 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
struct bt_l2cap_chan *chan;
struct bt_l2cap_server *server;
struct bt_l2cap_conn_req *req = (void *)buf->data;
uint16_t psm, scid, dcid, result;
uint16_t psm, scid, result;
if (buf->len < sizeof(*req)) {
BT_ERR("Too small L2CAP conn req packet size");
@ -756,7 +756,6 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
psm = sys_le16_to_cpu(req->psm);
scid = sys_le16_to_cpu(req->scid);
dcid = 0;
BT_DBG("psm 0x%02x scid 0x%04x", psm, scid);
@ -764,7 +763,7 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
server = l2cap_br_server_lookup_psm(psm);
if (!server) {
result = BT_L2CAP_BR_ERR_PSM_NOT_SUPP;
goto done;
goto no_chan;
}
/*
@ -774,18 +773,23 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
if (server->sec_level != BT_SECURITY_NONE &&
BT_FEAT_HOST_SSP(conn->br.features) && !conn->encrypt) {
result = BT_L2CAP_BR_ERR_SEC_BLOCK;
goto done;
goto no_chan;
}
if (!L2CAP_BR_CID_IS_DYN(scid)) {
result = BT_L2CAP_BR_ERR_INVALID_SCID;
goto done;
goto no_chan;
}
chan = bt_l2cap_br_lookup_tx_cid(conn, scid);
if (chan) {
/*
* we have a chan here but this is due to SCID being already in
* use so it is not channel we are suppose to pass to
* l2cap_br_conn_req_reply as wrong DCID would be used
*/
result = BT_L2CAP_BR_ERR_SCID_IN_USE;
goto done;
goto no_chan;
}
/*
@ -794,16 +798,14 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
* proper result and quit since chan pointer is uninitialized then.
*/
if (server->accept(conn, &chan) < 0) {
l2cap_br_send_conn_rsp(conn, scid, dcid, ident,
BT_L2CAP_BR_ERR_NO_RESOURCES);
return;
result = BT_L2CAP_BR_ERR_NO_RESOURCES;
goto no_chan;
}
chan->required_sec_level = server->sec_level;
l2cap_br_chan_add(conn, chan, l2cap_br_chan_destroy);
BR_CHAN(chan)->tx.cid = scid;
dcid = BR_CHAN(chan)->rx.cid;
chan->ident = ident;
bt_l2cap_chan_set_state(chan, BT_L2CAP_CONNECT);
atomic_set_bit(BR_CHAN(chan)->flags, L2CAP_FLAG_CONN_ACCEPTOR);
@ -824,20 +826,25 @@ static void l2cap_br_conn_req(struct bt_l2cap_br *l2cap, uint8_t ident,
result = BT_L2CAP_BR_ERR_SEC_BLOCK;
break;
}
done:
/* Reply on connection request as acceptor */
l2cap_br_conn_req_reply(chan, result);
/* Disconnect link when security rules were violated */
if (result == BT_L2CAP_BR_ERR_SEC_BLOCK) {
bt_conn_disconnect(conn, BT_HCI_ERR_AUTHENTICATION_FAIL);
if (result != BT_L2CAP_SUCCESS) {
/* Disconnect link when security rules were violated */
if (result == BT_L2CAP_BR_ERR_SEC_BLOCK) {
bt_conn_disconnect(conn,
BT_HCI_ERR_AUTHENTICATION_FAIL);
}
return;
}
if (result == BT_L2CAP_SUCCESS) {
bt_l2cap_chan_set_state(chan, BT_L2CAP_CONFIG);
l2cap_br_conf(chan);
}
bt_l2cap_chan_set_state(chan, BT_L2CAP_CONFIG);
l2cap_br_conf(chan);
return;
no_chan:
l2cap_br_send_conn_rsp(conn, scid, 0, ident, result);
}
static void l2cap_br_conf_rsp(struct bt_l2cap_br *l2cap, uint8_t ident,