diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_api.c b/components/bt/host/bluedroid/stack/avrc/avrc_api.c index a1099364ea0..d44579088a5 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_api.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_api.c @@ -910,11 +910,19 @@ static BT_HDR *avrc_pass_msg(tAVRC_MSG_PASS *p_msg) { BT_HDR *p_cmd = NULL; UINT8 *p_data; + UINT32 buf_size; + UINT16 pass_len; assert(p_msg != NULL); - assert(AVRC_CMD_BUF_SIZE > (AVRC_MIN_CMD_LEN+p_msg->pass_len)); - if ((p_cmd = (BT_HDR *) osi_malloc(AVRC_CMD_BUF_SIZE)) != NULL) { + /* ctype(1) + subunit(1) + opcode(1) + op_id(1) + data_len(1) + optional pass data */ + pass_len = (p_msg->op_id == AVRC_ID_VENDOR) ? p_msg->pass_len : 0; + buf_size = (UINT32)sizeof(BT_HDR) + AVCT_MSG_OFFSET + 5 + pass_len; + if (buf_size > AVRC_CMD_BUF_SIZE) { + return NULL; + } + + if ((p_cmd = (BT_HDR *) osi_malloc(buf_size)) != NULL) { p_cmd->offset = AVCT_MSG_OFFSET; p_cmd->layer_specific = AVCT_DATA_CTRL; p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; diff --git a/components/bt/host/bluedroid/stack/avrc/avrc_opt.c b/components/bt/host/bluedroid/stack/avrc/avrc_opt.c index ff3a26870f3..d92634a3dc1 100644 --- a/components/bt/host/bluedroid/stack/avrc/avrc_opt.c +++ b/components/bt/host/bluedroid/stack/avrc/avrc_opt.c @@ -60,18 +60,20 @@ static BT_HDR *avrc_vendor_msg(tAVRC_MSG_VENDOR *p_msg) */ #define AVRC_MIN_VENDOR_CMD_LEN (BT_HDR_SIZE + AVCT_MSG_OFFSET + AVRC_VENDOR_HDR_SIZE) + UINT32 buf_size; +#if AVRC_METADATA_INCLUDED == TRUE + const UINT16 max_cmd_buf = AVRC_META_CMD_BUF_SIZE; +#else + const UINT16 max_cmd_buf = AVRC_CMD_BUF_SIZE; +#endif + if (!p_msg) { return NULL; } -#if AVRC_METADATA_INCLUDED == TRUE - if ((AVRC_META_CMD_BUF_SIZE >= AVRC_MIN_VENDOR_CMD_LEN + p_msg->vendor_len) && - ((p_cmd = (BT_HDR *) osi_malloc(AVRC_META_CMD_BUF_SIZE)) != NULL)) -#else - if ((AVRC_CMD_BUF_SIZE >= (AVRC_MIN_VENDOR_CMD_LEN + p_msg->vendor_len)) && - ((p_cmd = (BT_HDR *) osi_malloc(AVRC_CMD_BUF_SIZE)) != NULL)) -#endif - { + buf_size = (UINT32)AVRC_MIN_VENDOR_CMD_LEN + p_msg->vendor_len; + if (buf_size <= max_cmd_buf && + ((p_cmd = (BT_HDR *) osi_malloc(buf_size)) != NULL)) { p_cmd->offset = AVCT_MSG_OFFSET; p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; *p_data++ = (p_msg->hdr.ctype & AVRC_CTYPE_MASK); @@ -115,8 +117,10 @@ UINT16 AVRC_UnitCmd(UINT8 handle, UINT8 label) { BT_HDR *p_cmd; UINT8 *p_data; + /* ctype + subunit + opcode + AVRC_UNIT_OPRND_BYTES */ + UINT32 buf_size = (UINT32)sizeof(BT_HDR) + AVCT_MSG_OFFSET + 3 + AVRC_UNIT_OPRND_BYTES; - if ((p_cmd = (BT_HDR *) osi_malloc(AVRC_CMD_BUF_SIZE)) != NULL) { + if ((p_cmd = (BT_HDR *) osi_malloc(buf_size)) != NULL) { p_cmd->offset = AVCT_MSG_OFFSET; p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; *p_data++ = AVRC_CMD_STATUS; @@ -159,8 +163,10 @@ UINT16 AVRC_SubCmd(UINT8 handle, UINT8 label, UINT8 page) { BT_HDR *p_cmd; UINT8 *p_data; + /* ctype + subunit + opcode + page + AVRC_SUB_OPRND_BYTES */ + UINT32 buf_size = (UINT32)sizeof(BT_HDR) + AVCT_MSG_OFFSET + 4 + AVRC_SUB_OPRND_BYTES; - if ((p_cmd = (BT_HDR *) osi_malloc(AVRC_CMD_BUF_SIZE)) != NULL) { + if ((p_cmd = (BT_HDR *) osi_malloc(buf_size)) != NULL) { p_cmd->offset = AVCT_MSG_OFFSET; p_data = (UINT8 *)(p_cmd + 1) + p_cmd->offset; *p_data++ = AVRC_CMD_STATUS; diff --git a/components/bt/host/bluedroid/stack/hid/hidd_conn.c b/components/bt/host/bluedroid/stack/hid/hidd_conn.c index 2d4f878ddf9..8b9eca378f6 100644 --- a/components/bt/host/bluedroid/stack/hid/hidd_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidd_conn.c @@ -729,7 +729,8 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param BT_HDR *p_buf; uint8_t *p_out; uint16_t cid; - uint16_t buf_size; + uint16_t max_buf_size; + uint32_t payload_size, buf_size; HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len); @@ -742,20 +743,34 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param case HID_TRANS_HANDSHAKE: case HID_TRANS_CONTROL: cid = p_hcon->ctrl_cid; - buf_size = HID_CONTROL_BUF_SIZE; + max_buf_size = HID_CONTROL_BUF_SIZE; break; case HID_TRANS_DATA: if (channel == HID_CHANNEL_CTRL) { cid = p_hcon->ctrl_cid; - buf_size = HID_CONTROL_BUF_SIZE; + max_buf_size = HID_CONTROL_BUF_SIZE; } else { cid = p_hcon->intr_cid; - buf_size = HID_INTERRUPT_BUF_SIZE; + max_buf_size = HID_INTERRUPT_BUF_SIZE; } break; default: return (HID_ERR_INVALID_PARAM); } + + /* HID header byte, plus an optional report id byte */ + payload_size = (uint32_t)len + 2; + buf_size = BT_HDR_SIZE + L2CAP_MIN_OFFSET + payload_size; + if (buf_size > max_buf_size) { + HIDD_TRACE_ERROR("hidd tx: len(%d) too large",len); + return (HID_ERR_INVALID_PARAM); + } + /* rem_mtu_size is only known once the channel has been configured */ + if (p_hcon->rem_mtu_size && payload_size > p_hcon->rem_mtu_size) { + HIDD_TRACE_ERROR("hidd tx: len(%d) exceeds peer mtu(%d)",len, p_hcon->rem_mtu_size); + return (HID_ERR_INVALID_PARAM); + } + p_buf = (BT_HDR *)osi_malloc(buf_size); if (p_buf == NULL) return (HID_ERR_NO_RESOURCES); diff --git a/components/bt/host/bluedroid/stack/hid/hidh_conn.c b/components/bt/host/bluedroid/stack/hid/hidh_conn.c index 57697c9b9d4..e24861fc8fe 100644 --- a/components/bt/host/bluedroid/stack/hid/hidh_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidh_conn.c @@ -865,11 +865,9 @@ tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param, case HID_TRANS_GET_IDLE: case HID_TRANS_SET_IDLE: cid = p_hcon->ctrl_cid; - buf_size = HID_CONTROL_BUF_SIZE; break; case HID_TRANS_DATA: cid = p_hcon->intr_cid; - buf_size = HID_INTERRUPT_BUF_SIZE; break; default: rc = HID_ERR_INVALID_PARAM; @@ -884,6 +882,8 @@ tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param, do { if ( buf == NULL || blank_datc ) { + /* HID header byte, an optional report id byte and the inlined data bytes */ + buf_size = BT_HDR_SIZE + L2CAP_MIN_OFFSET + 2 + use_data; if ((p_buf = (BT_HDR *)osi_malloc(buf_size)) == NULL) { rc = HID_ERR_NO_RESOURCES; goto error; @@ -895,6 +895,8 @@ tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param, bytes_copied = 0; blank_datc = FALSE; } else if ( (buf->len > (p_hcon->rem_mtu_size - 1))) { + /* HID header byte plus a full (rem_mtu_size - 1) payload segment */ + buf_size = BT_HDR_SIZE + L2CAP_MIN_OFFSET + p_hcon->rem_mtu_size + use_data; if ((p_buf = (BT_HDR *)osi_malloc(buf_size)) == NULL) { rc = HID_ERR_NO_RESOURCES; goto error; diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c index 92105a7d7be..bd219d216f8 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_fcr.c @@ -42,6 +42,9 @@ /* Flag passed to retransmit_i_frames() when all packets should be retransmitted */ #define L2C_FCR_RETX_ALL_PKTS 0xFF +/* Offset reserved in front of a reassembled SDU, the minimal offset required by OBEX */ +#define L2C_FCR_RX_SDU_OFFSET 4 + #if BT_TRACE_VERBOSE == TRUE static char *SAR_types[] = { "Unsegmented", "Start", "End", "Continuation" }; static char *SUP_types[] = { "RR", "REJ", "RNR", "SREJ" }; @@ -538,7 +541,11 @@ void l2c_fcr_send_S_frame (tL2C_CCB *p_ccb, UINT16 function_code, UINT16 pf_bit) ctrl_word |= (p_ccb->fcrb.next_seq_expected << L2CAP_FCR_REQ_SEQ_BITS_SHIFT); ctrl_word |= pf_bit; - if ((p_buf = (BT_HDR *)osi_malloc(L2CAP_CMD_BUF_SIZE)) != NULL) { + /* An S-frame carries no payload: HCI preamble, L2CAP header, control word and FCS */ + UINT16 s_frame_buf_size = sizeof(BT_HDR) + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + + L2CAP_FCR_OVERHEAD + L2CAP_FCS_LEN; + + if ((p_buf = (BT_HDR *)osi_malloc(s_frame_buf_size)) != NULL) { p_buf->offset = HCI_DATA_PREAMBLE_SIZE; p_buf->len = L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD; @@ -1350,11 +1357,12 @@ static BOOLEAN do_sar_reassembly (tL2C_CCB *p_ccb, BT_HDR *p_buf, UINT16 ctrl_wo if (p_fcrb->rx_sdu_len > p_ccb->max_rx_mtu) { L2CAP_TRACE_WARNING ("SAR - SDU len: %u larger than MTU: %u", p_fcrb->rx_sdu_len, p_ccb->max_rx_mtu); packet_ok = FALSE; - } else if ((p_fcrb->p_rx_sdu = (BT_HDR *)osi_malloc(L2CAP_MAX_BUF_SIZE)) == NULL) { + } else if ((p_fcrb->p_rx_sdu = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2C_FCR_RX_SDU_OFFSET + + p_fcrb->rx_sdu_len)) == NULL) { L2CAP_TRACE_ERROR ("SAR - no buffer for SDU start user_rx_buf_size:%d", p_ccb->ertm_info.user_rx_buf_size); packet_ok = FALSE; } else { - p_fcrb->p_rx_sdu->offset = 4; /* this is the minimal offset required by OBX to process incoming packets */ + p_fcrb->p_rx_sdu->offset = L2C_FCR_RX_SDU_OFFSET; p_fcrb->p_rx_sdu->len = 0; } } diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c index 124e036441d..0a110ecd9ba 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c @@ -469,12 +469,18 @@ BT_HDR *l2cu_build_header (tL2C_LCB *p_lcb, UINT16 len, UINT8 cmd, UINT8 id) { BT_HDR *p_buf; UINT8 *p; + UINT32 buf_size; - if (len + BT_HDR_SIZE + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD > L2CAP_CMD_BUF_SIZE) { + /* Command parameter length is known; allocate only what this signalling PDU needs. + * Keep L2CAP_CMD_BUF_SIZE as the design upper bound (same as before). + */ + buf_size = (UINT32)sizeof(BT_HDR) + L2CAP_SEND_CMD_OFFSET + len + + HCI_DATA_PREAMBLE_SIZE + L2CAP_PKT_OVERHEAD + L2CAP_CMD_OVERHEAD; + if (buf_size > L2CAP_CMD_BUF_SIZE) { return NULL; } - if ((p_buf = (BT_HDR *)osi_malloc(L2CAP_CMD_BUF_SIZE)) == NULL) { + if ((p_buf = (BT_HDR *)osi_malloc(buf_size)) == NULL) { return (NULL); } diff --git a/components/bt/host/bluedroid/stack/rfcomm/port_api.c b/components/bt/host/bluedroid/stack/rfcomm/port_api.c index 53c83b87372..9db559587fb 100644 --- a/components/bt/host/bluedroid/stack/rfcomm/port_api.c +++ b/components/bt/host/bluedroid/stack/rfcomm/port_api.c @@ -1627,6 +1627,7 @@ int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) UINT32 event = 0; int rc = 0; UINT16 length; + UINT16 hdr_overhead, capacity; RFCOMM_TRACE_API ("PORT_WriteData() max_len:%d", max_len); @@ -1669,6 +1670,13 @@ int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) osi_mutex_global_unlock(); + hdr_overhead = (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD + L2CAP_FCS_LEN); + capacity = RFCOMM_DATA_BUF_SIZE - hdr_overhead; + /* Data beyond the peer MTU can never be placed in the buffer, so don't allocate room for it */ + if (p_port->peer_mtu < capacity) { + capacity = p_port->peer_mtu; + } + while (max_len) { /* if we're over buffer high water mark, we're done */ if ((p_port->tx.queue_size > PORT_TX_HIGH_WM) @@ -1677,18 +1685,15 @@ int PORT_WriteData (UINT16 handle, char *p_data, UINT16 max_len, UINT16 *p_len) } /* continue with rfcomm data write */ - p_buf = (BT_HDR *)osi_malloc(RFCOMM_DATA_BUF_SIZE); + p_buf = (BT_HDR *)osi_malloc(hdr_overhead + capacity); if (!p_buf) { break; } p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET; - p_buf->layer_specific = RFCOMM_DATA_BUF_SIZE - (UINT16)(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + RFCOMM_DATA_OVERHEAD + L2CAP_FCS_LEN); - /* Length for each buffer is the smaller of GKI buffer, peer MTU, or max_len */ + p_buf->layer_specific = capacity; + /* Length for each buffer is the smaller of the buffer capacity or max_len */ length = p_buf->layer_specific; - if (p_port->peer_mtu < length) { - length = p_port->peer_mtu; - } if (max_len < length) { length = max_len; } diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c index dc311d8a635..f8c4397b5ca 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_discovery.c @@ -56,6 +56,17 @@ static UINT8 *add_attr (UINT8 *p, UINT8 *p_end, tSDP_DISCOVERY_DB *p_db, /* Safety check in case we go crazy */ #define MAX_NEST_LEVELS 5 +/* Worst case length of any SDP request built by this module: + * pdu id(1) + transaction id(2) + parameter length(2) + * + UUID sequence: 2 byte header + SDP_MAX_UUID_FILTERS 128-bit UUIDs + * + maximum record/byte count(2) + * + attribute sequence: 3 byte header + SDP_MAX_ATTR_FILTERS entries of 3 bytes + * + continuation state: 1 byte length + SDP_MAX_CONTINUATION_LEN(16) + * A service attribute request carries a 4 byte record handle instead of the UUID + * sequence, so it is covered as well. */ +#define SDP_MAX_REQ_LEN (5 + (2 + SDP_MAX_UUID_FILTERS * (1 + LEN_UUID_128)) + 2 \ + + (3 + SDP_MAX_ATTR_FILTERS * 3) + (1 + SDP_MAX_CONTINUATION_LEN)) + /******************************************************************************* ** @@ -117,7 +128,7 @@ static void sdp_snd_service_search_req(tCONN_CB *p_ccb, UINT8 cont_len, UINT8 *p UINT16 param_len; /* Get a buffer to send the packet to L2CAP */ - if ((p_cmd = (BT_HDR *) osi_malloc(SDP_DATA_BUF_SIZE)) == NULL) { + if ((p_cmd = (BT_HDR *) osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + SDP_MAX_REQ_LEN)) == NULL) { sdp_disconnect (p_ccb, SDP_NO_RESOURCES); return; } @@ -507,7 +518,7 @@ static void process_service_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UINT8 *p_ /* Now, ask for the next handle. Reuse the buffer we just got. */ if (p_ccb->cur_handle < p_ccb->num_handles) { - BT_HDR *p_msg = (BT_HDR *) osi_malloc(SDP_DATA_BUF_SIZE); + BT_HDR *p_msg = (BT_HDR *) osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + SDP_MAX_REQ_LEN); UINT8 *p; if (!p_msg) { @@ -656,7 +667,7 @@ static void process_service_search_attr_rsp (tCONN_CB *p_ccb, UINT8 *p_reply, UI #endif /* If continuation request (or first time request) */ if ((cont_request_needed) || (!p_reply)) { - BT_HDR *p_msg = (BT_HDR *) osi_malloc(SDP_DATA_BUF_SIZE); + BT_HDR *p_msg = (BT_HDR *) osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + SDP_MAX_REQ_LEN); UINT8 *p; if (!p_msg) { diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_server.c b/components/bt/host/bluedroid/stack/sdp/sdp_server.c index 3523ccbb93d..aef85fd5468 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_server.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_server.c @@ -256,8 +256,8 @@ static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num, is_cont = TRUE; } - /* Get a buffer to use to build the response */ - if ((p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE)) == NULL) { + /* Get a buffer to use to build the response, the whole PDU has to fit the peer MTU */ + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + p_ccb->rem_mtu_size)) == NULL) { SDP_TRACE_ERROR ("SDP - no buf for search rsp\n"); return; } @@ -523,8 +523,8 @@ static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, } } - /* Get a buffer to use to build the response */ - if ((p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE)) == NULL) { + /* Get a buffer to use to build the response, the whole PDU has to fit the peer MTU */ + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + p_ccb->rem_mtu_size)) == NULL) { SDP_TRACE_ERROR ("SDP - no buf for search rsp\n"); osi_free(p_ccb->rsp_list); p_ccb->rsp_list = NULL; @@ -865,8 +865,8 @@ static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num, } } - /* Get a buffer to use to build the response */ - if ((p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE)) == NULL) { + /* Get a buffer to use to build the response, the whole PDU has to fit the peer MTU */ + if ((p_buf = (BT_HDR *)osi_malloc(sizeof(BT_HDR) + L2CAP_MIN_OFFSET + p_ccb->rem_mtu_size)) == NULL) { SDP_TRACE_ERROR ("SDP - no buf for search rsp\n"); osi_free (p_ccb->rsp_list); p_ccb->rsp_list = NULL; diff --git a/components/bt/host/bluedroid/stack/sdp/sdp_utils.c b/components/bt/host/bluedroid/stack/sdp/sdp_utils.c index 8b91b36cc94..9da2d33cc61 100644 --- a/components/bt/host/bluedroid/stack/sdp/sdp_utils.c +++ b/components/bt/host/bluedroid/stack/sdp/sdp_utils.c @@ -306,14 +306,27 @@ void sdpu_build_n_send_error (tCONN_CB *p_ccb, UINT16 trans_num, UINT16 error_co { UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len; UINT16 rsp_param_len; + UINT16 buf_size; BT_HDR *p_buf; + UINT16 len; SDP_TRACE_WARNING ("SDP - sdpu_build_n_send_error code: 0x%x CID: 0x%x\n", error_code, p_ccb->connection_id); + /* pdu id(1), trans num(2), param len(2), error code(2) and the optional error text */ + buf_size = sizeof(BT_HDR) + L2CAP_MIN_OFFSET + 7; + if (p_error_text) { + len = (UINT16)strlen(p_error_text); + if (len > SDP_DATA_BUF_SIZE - buf_size) { + buf_size = SDP_DATA_BUF_SIZE; + }else { + buf_size += len; + } + } + /* Get a buffer to use to build and send the packet to L2CAP */ - if ((p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE)) == NULL) { + if ((p_buf = (BT_HDR *)osi_malloc(buf_size)) == NULL) { SDP_TRACE_ERROR ("SDP - no buf for err msg\n"); return; }