lkml.org 
[lkml]   [2013]   [Jun]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 11/48] Bluetooth: Fix missing length checks for L2CAP signalling PDUs
    Date
    From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    3.9-stable review patch. If anyone has any objections, please let me know.

    ------------------

    From: Johan Hedberg <johan.hedberg@intel.com>

    commit cb3b3152b2f5939d67005cff841a1ca748b19888 upstream.

    There has been code in place to check that the L2CAP length header
    matches the amount of data received, but many PDU handlers have not been
    checking that the data received actually matches that expected by the
    specific PDU. This patch adds passing the length header to the specific
    handler functions and ensures that those functions fail cleanly in the
    case of an incorrect amount of data.

    Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
    Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
    Signed-off-by: John W. Linville <linville@tuxdriver.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    net/bluetooth/l2cap_core.c | 70 +++++++++++++++++++++++++++++++++------------
    1 file changed, 52 insertions(+), 18 deletions(-)

    --- a/net/bluetooth/l2cap_core.c
    +++ b/net/bluetooth/l2cap_core.c
    @@ -3568,10 +3568,14 @@ static void l2cap_conf_rfc_get(struct l2
    }

    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;

    @@ -3720,11 +3724,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))
    @@ -3738,7 +3745,8 @@ static int l2cap_connect_req(struct l2ca
    }

    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;
    @@ -3746,6 +3754,9 @@ static int l2cap_connect_create_rsp(stru
    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);
    @@ -3843,6 +3854,9 @@ static inline int l2cap_config_req(struc
    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);

    @@ -3866,7 +3880,7 @@ static inline int l2cap_config_req(struc

    /* 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);
    @@ -3944,14 +3958,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);
    @@ -4052,7 +4070,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;
    @@ -4060,6 +4079,9 @@ static inline int l2cap_disconnect_req(s
    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);

    @@ -4099,12 +4121,16 @@ static inline int l2cap_disconnect_req(s
    }

    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);

    @@ -4134,11 +4160,15 @@ static inline int l2cap_disconnect_rsp(s
    }

    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);
    @@ -4185,11 +4215,15 @@ static inline int l2cap_information_req(
    }

    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);

    @@ -5055,16 +5089,16 @@ static inline int l2cap_bredr_sig_cmd(st

    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:
    @@ -5072,15 +5106,15 @@ static inline int l2cap_bredr_sig_cmd(st
    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:
    @@ -5091,11 +5125,11 @@ static inline int l2cap_bredr_sig_cmd(st
    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:



    \
     
     \ /
      Last update: 2013-06-19 07:41    [W:3.497 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site