Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 227c69ce authored by Andre Eisenbach's avatar Andre Eisenbach Committed by Nick Kralevich
Browse files

LE: Improved handling of illegal GATT PDUs

Do additional length checks when handling malformed messages. These
messages are never valid, and should be dropped if seen.

Before starting to parse out PDU content, it is verified that the
buffer contains sufficient bytes and error condition is returned
if this is not the case.

Bug: 11045073
Change-Id: Ifb792d1575e0514f33e75ed73247ea638807901e
parent 9927a55f
Loading
Loading
Loading
Loading
+46 −11
Original line number Diff line number Diff line
@@ -34,6 +34,13 @@
#define GATT_READ_CHAR_VALUE_HDL    (GATT_READ_CHAR_VALUE | 0x80)
#define GATT_READ_INC_SRV_UUID128   (GATT_DISC_INC_SRVC   | 0x90)

#define GATT_PREP_WRITE_RSP_MIN_LEN 4
#define GATT_NOTIFICATION_MIN_LEN 2
#define GATT_WRITE_RSP_MIN_LEN  2
#define GATT_INFO_RSP_MIN_LEN   1
#define GATT_MTU_RSP_MIN_LEN    2
#define GATT_READ_BY_TYPE_RSP_MIN_LEN    1

/********************************************************************************
**                       G L O B A L      G A T T       D A T A                 *
*********************************************************************************/
@@ -444,6 +451,12 @@ void gatt_process_read_info_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_c
    tGATT_DISC_RES  result;
    UINT8   *p = p_data, uuid_len = 0, type;

    if (len < GATT_INFO_RSP_MIN_LEN)
    {
        GATT_TRACE_ERROR0("invalid Info Response PDU received, discard.");
        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
        return;
    }
    /* unexpected response */
    if (p_clcb->operation != GATTC_OPTYPE_DISCOVERY || p_clcb->op_subtype != GATT_DISC_CHAR_DSCPT)
        return;
@@ -583,6 +596,13 @@ void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op

    GATT_TRACE_ERROR2("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len);

    if (len < GATT_PREP_WRITE_RSP_MIN_LEN)
    {
        GATT_TRACE_ERROR0("illegal prepare write response length, discard");
        gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value);
        return;
    }

    STREAM_TO_UINT16 (value.handle, p);
    STREAM_TO_UINT16 (value.offset, p);

@@ -628,6 +648,12 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code,

    GATT_TRACE_DEBUG0("gatt_process_notification ");

    if (len < GATT_NOTIFICATION_MIN_LEN)
    {
        GATT_TRACE_ERROR0("illegal notification PDU length, discard");
        return;
    }

    STREAM_TO_UINT16 (value.handle, p);
    value.len = len - 2;
    memcpy (value.value, p, value.len);
@@ -708,6 +734,13 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8
    if (((!p_clcb->p_reg) || (!p_clcb->p_reg->app_cb.p_disc_res_cb)) && (p_clcb->operation == GATTC_OPTYPE_DISCOVERY))
        return;

    if (len < GATT_READ_BY_TYPE_RSP_MIN_LEN)
    {
        GATT_TRACE_ERROR0("Illegal ReadByType/ReadByGroupType Response length, discard");
        gatt_end_operation(p_clcb, GATT_INVALID_PDU, NULL);
        return;
    }

    STREAM_TO_UINT8(value_len, p);

    if ((value_len > (p_tcb->payload_size - 2)) || (value_len > (len-1))  )
@@ -979,15 +1012,8 @@ void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code,
** Returns          void
**
*******************************************************************************/
void gatt_process_handle_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, UINT16 len, UINT8 *p_data)
void gatt_process_handle_rsp(tGATT_CLCB *p_clcb)
{
    UINT16      handle;
    UINT8       * p= p_data;

    STREAM_TO_UINT16(handle, p);
    len -= 2;

    if (op_code == GATT_RSP_WRITE)
    gatt_end_operation(p_clcb, GATT_SUCCESS, NULL);
}
/*******************************************************************************
@@ -1003,13 +1029,22 @@ void gatt_process_handle_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code
void gatt_process_mtu_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT16 len, UINT8 *p_data)
{
    UINT16 mtu;
    tGATT_STATUS    status = GATT_SUCCESS;

    if (len < GATT_MTU_RSP_MIN_LEN)
    {
        GATT_TRACE_ERROR0("invalid MTU response PDU received, discard.");
        status = GATT_INVALID_PDU;
    }
    else
    {
    STREAM_TO_UINT16(mtu, p_data);

    if (mtu < p_tcb->payload_size && mtu >= GATT_DEF_BLE_MTU_SIZE)
        p_tcb->payload_size = mtu;
    }

    gatt_end_operation(p_clcb, p_clcb->status, NULL);
    gatt_end_operation(p_clcb, status, NULL);
}
/*******************************************************************************
**
@@ -1161,7 +1196,7 @@ void gatt_client_handle_server_rsp (tGATT_TCB *p_tcb, UINT8 op_code,
                break;

            case GATT_RSP_WRITE:
                gatt_process_handle_rsp(p_tcb, p_clcb, op_code, len, p_data);
                gatt_process_handle_rsp(p_clcb);
                break;

            case GATT_RSP_PREPARE_WRITE:
+57 −40
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@
#include "gatt_int.h"
#include "l2c_api.h"

#define GATT_MTU_REQ_MIN_LEN        2


/*******************************************************************************
**
@@ -545,8 +547,8 @@ static tGATT_STATUS gatt_build_primary_service_rsp (BT_HDR *p_msg, tGATT_TCB *p_
            p_rcb->s_hdl <= e_hdl &&
            p_rcb->type == GATT_UUID_PRI_SERVICE)
        {
            p_uuid = gatts_get_service_uuid (p_rcb->p_db);

            if ((p_uuid = gatts_get_service_uuid (p_rcb->p_db)) != NULL)
            {
                if (op_code == GATT_REQ_READ_BY_GRP_TYPE)
                    handle_len = 4 + p_uuid->len;

@@ -593,6 +595,7 @@ static tGATT_STATUS gatt_build_primary_service_rsp (BT_HDR *p_msg, tGATT_TCB *p_
                else
                    break;
            }
        }
        p_srv = p_srv->p_next;
    }
    p_msg->offset = L2CAP_MIN_OFFSET;
@@ -730,6 +733,8 @@ static tGATT_STATUS gatts_validate_packet_format(UINT8 op_code, UINT16 *p_len,
                reason = GATT_INVALID_PDU;
        }
    }
    else
        reason = GATT_INVALID_PDU;

    *p_data     = p;
    *p_len      = len;
@@ -901,15 +906,19 @@ static void gatts_process_mtu_req (tGATT_TCB *p_tcb, UINT16 len, UINT8 *p_data)
    BT_HDR        *p_buf;
    UINT16   conn_id;

    STREAM_TO_UINT16 (mtu, p);

    /* BR/EDR conenction, send error response */
    if (p_tcb->att_lcid != L2CAP_ATT_CID)
    {
        gatt_send_error_rsp (p_tcb, GATT_REQ_NOT_SUPPORTED, GATT_REQ_MTU, 0, FALSE);
    }
    else if (len < GATT_MTU_REQ_MIN_LEN)
    {
        GATT_TRACE_ERROR0("invalid MTU request PDU received.");
        gatt_send_error_rsp (p_tcb, GATT_INVALID_PDU, GATT_REQ_MTU, 0, FALSE);
    }
    else
    {
        STREAM_TO_UINT16 (mtu, p);
        /* mtu must be greater than default MTU which is 23/48 */
        if (mtu < GATT_DEF_BLE_MTU_SIZE)
            p_tcb->payload_size = GATT_DEF_BLE_MTU_SIZE;
@@ -1231,14 +1240,22 @@ static void gatts_process_read_req(tGATT_TCB *p_tcb, tGATT_SR_REG *p_rcb, UINT8
void gatts_process_attribute_req (tGATT_TCB *p_tcb, UINT8 op_code,
                                  UINT16 len, UINT8 *p_data)
{
    UINT16          handle;
    UINT16          handle = 0;
    UINT8           *p = p_data, i;
    tGATT_SR_REG    *p_rcb = gatt_cb.sr_reg;
    tGATT_STATUS    status = GATT_INVALID_HANDLE;
    tGATT_ATTR16    *p_attr;

    if (len < 2)
    {
        GATT_TRACE_ERROR0("Illegal PDU length, discard request");
        status = GATT_INVALID_PDU;
    }
    else
    {
        STREAM_TO_UINT16(handle, p);
        len -= 2;
    }

#if GATT_CONFORMANCE_TESTING == TRUE
    gatt_cb.handle = handle;