|
@@ -3677,10 +3677,14 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
|
|
|
}
|
|
|
|
|
|
static inline int l2cap_command_rej(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
|
|
|
|
|
|
+ if (cmd_len < sizeof(*rej))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
|
|
|
return 0;
|
|
|
|
|
@@ -3829,11 +3833,14 @@ sendresp:
|
|
|
}
|
|
|
|
|
|
static int l2cap_connect_req(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
|
|
|
{
|
|
|
struct hci_dev *hdev = conn->hcon->hdev;
|
|
|
struct hci_conn *hcon = conn->hcon;
|
|
|
|
|
|
+ if (cmd_len < sizeof(struct l2cap_conn_req))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
hci_dev_lock(hdev);
|
|
|
if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
|
|
|
!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
|
|
@@ -3847,7 +3854,8 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
|
|
|
}
|
|
|
|
|
|
static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
|
|
|
u16 scid, dcid, result, status;
|
|
@@ -3855,6 +3863,9 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
|
|
|
u8 req[128];
|
|
|
int err;
|
|
|
|
|
|
+ if (cmd_len < sizeof(*rsp))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
scid = __le16_to_cpu(rsp->scid);
|
|
|
dcid = __le16_to_cpu(rsp->dcid);
|
|
|
result = __le16_to_cpu(rsp->result);
|
|
@@ -3952,6 +3963,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|
|
struct l2cap_chan *chan;
|
|
|
int len, err = 0;
|
|
|
|
|
|
+ if (cmd_len < sizeof(*req))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
dcid = __le16_to_cpu(req->dcid);
|
|
|
flags = __le16_to_cpu(req->flags);
|
|
|
|
|
@@ -3975,7 +3989,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
|
|
|
|
|
|
/* Reject if config buffer is too small. */
|
|
|
len = cmd_len - sizeof(*req);
|
|
|
- if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
|
|
|
+ if (chan->conf_len + len > sizeof(chan->conf_req)) {
|
|
|
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
|
|
|
l2cap_build_conf_rsp(chan, rsp,
|
|
|
L2CAP_CONF_REJECT, flags), rsp);
|
|
@@ -4053,14 +4067,18 @@ unlock:
|
|
|
}
|
|
|
|
|
|
static inline int l2cap_config_rsp(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
|
|
|
u16 scid, flags, result;
|
|
|
struct l2cap_chan *chan;
|
|
|
- int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
|
|
|
+ int len = cmd_len - sizeof(*rsp);
|
|
|
int err = 0;
|
|
|
|
|
|
+ if (cmd_len < sizeof(*rsp))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
scid = __le16_to_cpu(rsp->scid);
|
|
|
flags = __le16_to_cpu(rsp->flags);
|
|
|
result = __le16_to_cpu(rsp->result);
|
|
@@ -4161,7 +4179,8 @@ done:
|
|
|
}
|
|
|
|
|
|
static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
|
|
|
struct l2cap_disconn_rsp rsp;
|
|
@@ -4169,6 +4188,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
|
|
|
struct l2cap_chan *chan;
|
|
|
struct sock *sk;
|
|
|
|
|
|
+ if (cmd_len != sizeof(*req))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
scid = __le16_to_cpu(req->scid);
|
|
|
dcid = __le16_to_cpu(req->dcid);
|
|
|
|
|
@@ -4208,12 +4230,16 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
|
|
|
}
|
|
|
|
|
|
static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
|
|
|
u16 dcid, scid;
|
|
|
struct l2cap_chan *chan;
|
|
|
|
|
|
+ if (cmd_len != sizeof(*rsp))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
scid = __le16_to_cpu(rsp->scid);
|
|
|
dcid = __le16_to_cpu(rsp->dcid);
|
|
|
|
|
@@ -4243,11 +4269,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
|
|
|
}
|
|
|
|
|
|
static inline int l2cap_information_req(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_info_req *req = (struct l2cap_info_req *) data;
|
|
|
u16 type;
|
|
|
|
|
|
+ if (cmd_len != sizeof(*req))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
type = __le16_to_cpu(req->type);
|
|
|
|
|
|
BT_DBG("type 0x%4.4x", type);
|
|
@@ -4294,11 +4324,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn,
|
|
|
}
|
|
|
|
|
|
static inline int l2cap_information_rsp(struct l2cap_conn *conn,
|
|
|
- struct l2cap_cmd_hdr *cmd, u8 *data)
|
|
|
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
|
|
|
+ u8 *data)
|
|
|
{
|
|
|
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
|
|
|
u16 type, result;
|
|
|
|
|
|
+ if (cmd_len != sizeof(*rsp))
|
|
|
+ return -EPROTO;
|
|
|
+
|
|
|
type = __le16_to_cpu(rsp->type);
|
|
|
result = __le16_to_cpu(rsp->result);
|
|
|
|
|
@@ -5164,16 +5198,16 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
|
|
|
|
|
|
switch (cmd->code) {
|
|
|
case L2CAP_COMMAND_REJ:
|
|
|
- l2cap_command_rej(conn, cmd, data);
|
|
|
+ l2cap_command_rej(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_CONN_REQ:
|
|
|
- err = l2cap_connect_req(conn, cmd, data);
|
|
|
+ err = l2cap_connect_req(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_CONN_RSP:
|
|
|
case L2CAP_CREATE_CHAN_RSP:
|
|
|
- err = l2cap_connect_create_rsp(conn, cmd, data);
|
|
|
+ err = l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_CONF_REQ:
|
|
@@ -5181,15 +5215,15 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
|
|
|
break;
|
|
|
|
|
|
case L2CAP_CONF_RSP:
|
|
|
- err = l2cap_config_rsp(conn, cmd, data);
|
|
|
+ err = l2cap_config_rsp(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_DISCONN_REQ:
|
|
|
- err = l2cap_disconnect_req(conn, cmd, data);
|
|
|
+ err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_DISCONN_RSP:
|
|
|
- err = l2cap_disconnect_rsp(conn, cmd, data);
|
|
|
+ err = l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_ECHO_REQ:
|
|
@@ -5200,11 +5234,11 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
|
|
|
break;
|
|
|
|
|
|
case L2CAP_INFO_REQ:
|
|
|
- err = l2cap_information_req(conn, cmd, data);
|
|
|
+ err = l2cap_information_req(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_INFO_RSP:
|
|
|
- err = l2cap_information_rsp(conn, cmd, data);
|
|
|
+ err = l2cap_information_rsp(conn, cmd, cmd_len, data);
|
|
|
break;
|
|
|
|
|
|
case L2CAP_CREATE_CHAN_REQ:
|