diff --git a/components/bt/host/bluedroid/bta/av/bta_av_ca_act.c b/components/bt/host/bluedroid/bta/av/bta_av_ca_act.c index bdb1cd6f851..5e01bec3d97 100644 --- a/components/bt/host/bluedroid/bta/av/bta_av_ca_act.c +++ b/components/bt/host/bluedroid/bta/av/bta_av_ca_act.c @@ -314,7 +314,10 @@ error: void bta_av_ca_response(tBTA_AV_RCB *p_rcb, tBTA_AV_DATA *p_data) { tOBEX_PARSE_INFO info; - OBEX_ParseResponse(p_data->ca_response.pkt, p_data->ca_response.opcode, &info); + if (OBEX_ParseResponse(p_data->ca_response.pkt, p_data->ca_response.opcode, &info) != OBEX_SUCCESS) { + osi_free(p_data->ca_response.pkt); + goto error; + } /* we always use a final get */ if (p_data->ca_response.opcode == OBEX_OPCODE_GET_FINAL && (info.response_code == OBEX_RESPONSE_CODE_CONTINUE || info.response_code == (OBEX_RESPONSE_CODE_CONTINUE | OBEX_FINAL_BIT_MASK))) @@ -322,13 +325,15 @@ void bta_av_ca_response(tBTA_AV_RCB *p_rcb, tBTA_AV_DATA *p_data) UINT8 *header = NULL; UINT8 *body_data = NULL; UINT16 body_data_len = 0; + UINT8 *pkt_data = (UINT8 *)(p_data->ca_response.pkt + 1) + p_data->ca_response.pkt->offset; + UINT8 *pkt_end = pkt_data + p_data->ca_response.pkt->len; while((header = OBEX_GetNextHeader(p_data->ca_response.pkt, &info)) != NULL) { switch (*header) { case OBEX_HEADER_ID_BODY: /* actually,END_OF_BODY should not in this continue response */ case OBEX_HEADER_ID_END_OF_BODY: { - UINT16 hdr_len = OBEX_GetHeaderLength(header); + UINT16 hdr_len = OBEX_GetHeaderLength(header, pkt_end); UINT16 seg_len = (hdr_len >= 3) ? (UINT16)(hdr_len - 3) : 0; if (body_data == NULL) { /* first body header */ @@ -373,7 +378,10 @@ error: void bta_av_ca_response_final(tBTA_AV_RCB *p_rcb, tBTA_AV_DATA *p_data) { tOBEX_PARSE_INFO info; - OBEX_ParseResponse(p_data->ca_response.pkt, p_data->ca_response.opcode, &info); + if (OBEX_ParseResponse(p_data->ca_response.pkt, p_data->ca_response.opcode, &info) != OBEX_SUCCESS) { + osi_free(p_data->ca_response.pkt); + goto error; + } UINT8 *header = NULL; if (p_data->ca_response.opcode == OBEX_OPCODE_CONNECT) { /* we expect a success response code with final bit set */ @@ -385,14 +393,21 @@ void bta_av_ca_response_final(tBTA_AV_RCB *p_rcb, tBTA_AV_DATA *p_data) p_rcb->cover_art_max_tx = info.max_packet_length; } BOOLEAN cid_found = false; + UINT8 *pkt_data = (UINT8 *)(p_data->ca_response.pkt + 1) + p_data->ca_response.pkt->offset; + UINT8 *pkt_end = pkt_data + p_data->ca_response.pkt->len; while((header = OBEX_GetNextHeader(p_data->ca_response.pkt, &info)) != NULL) { if (*header == OBEX_HEADER_ID_CONNECTION_ID) { + if (OBEX_GetHeaderLength(header, pkt_end) != 5) { + osi_free(p_data->ca_response.pkt); + goto error; + } cid_found = true; memcpy((UINT8 *)(&p_rcb->cover_art_cid), header + 1, 4); break; } } if (!cid_found) { + osi_free(p_data->ca_response.pkt); goto error; } tBTA_AV_CA_STATUS ca_status; @@ -412,13 +427,15 @@ void bta_av_ca_response_final(tBTA_AV_RCB *p_rcb, tBTA_AV_DATA *p_data) UINT16 body_data_len = 0; /* check response code is success */ if (info.response_code == (OBEX_RESPONSE_CODE_OK | OBEX_FINAL_BIT_MASK)) { + UINT8 *pkt_data = (UINT8 *)(p_data->ca_response.pkt + 1) + p_data->ca_response.pkt->offset; + UINT8 *pkt_end = pkt_data + p_data->ca_response.pkt->len; while((header = OBEX_GetNextHeader(p_data->ca_response.pkt, &info)) != NULL) { switch (*header) { /* actually, BODY should not in this final response */ case OBEX_HEADER_ID_BODY: case OBEX_HEADER_ID_END_OF_BODY: { - UINT16 hdr_len = OBEX_GetHeaderLength(header); + UINT16 hdr_len = OBEX_GetHeaderLength(header, pkt_end); UINT16 seg_len = (hdr_len >= 3) ? (UINT16)(hdr_len - 3) : 0; if (body_data == NULL) { /* first body header */ diff --git a/components/bt/host/bluedroid/bta/pba/bta_pba_client_act.c b/components/bt/host/bluedroid/bta/pba/bta_pba_client_act.c index 7786a610e47..af220475342 100644 --- a/components/bt/host/bluedroid/bta/pba/bta_pba_client_act.c +++ b/components/bt/host/bluedroid/bta/pba/bta_pba_client_act.c @@ -463,7 +463,9 @@ void bta_pba_client_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p tOBEX_PARSE_INFO info; tBTA_PBA_CLIENT_ERR reason = BTA_PBA_CLIENT_GOEP_ERROR; - OBEX_ParseResponse(p_data->goep_response.pkt, p_data->goep_response.opcode, &info); + if (OBEX_ParseResponse(p_data->goep_response.pkt, p_data->goep_response.opcode, &info) != OBEX_SUCCESS) { + goto error; + } if (p_data->goep_response.opcode == OBEX_OPCODE_GET_FINAL && (info.response_code == OBEX_RESPONSE_CODE_CONTINUE || info.response_code == (OBEX_RESPONSE_CODE_CONTINUE | OBEX_FINAL_BIT_MASK))) { UINT8 *header = NULL; @@ -471,13 +473,15 @@ void bta_pba_client_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p UINT16 body_data_len = 0; UINT8 *app_param = NULL; UINT16 app_param_len = 0; + UINT8 *pkt_data = (UINT8 *)(p_data->goep_response.pkt + 1) + p_data->goep_response.pkt->offset; + UINT8 *pkt_end = pkt_data + p_data->goep_response.pkt->len; while((header = OBEX_GetNextHeader(p_data->goep_response.pkt, &info)) != NULL) { switch (*header) { case OBEX_HEADER_ID_BODY: case OBEX_HEADER_ID_END_OF_BODY: { - UINT16 hi_len = OBEX_GetHeaderLength(header); + UINT16 hi_len = OBEX_GetHeaderLength(header, pkt_end); if (hi_len < 3) { reason = BTA_PBA_CLIENT_BAD_REQUEST; goto error; @@ -497,7 +501,7 @@ void bta_pba_client_response(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_DATA *p } case OBEX_HEADER_ID_APP_PARAM: { - UINT16 hi_len = OBEX_GetHeaderLength(header); + UINT16 hi_len = OBEX_GetHeaderLength(header, pkt_end); if (hi_len < 3) { reason = BTA_PBA_CLIENT_BAD_REQUEST; goto error; @@ -544,7 +548,9 @@ void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_D UINT8 *header = NULL; tBTA_PBA_CLIENT_ERR reason = BTA_PBA_CLIENT_FAIL; - OBEX_ParseResponse(p_data->goep_response.pkt, p_data->goep_response.opcode, &info); + if (OBEX_ParseResponse(p_data->goep_response.pkt, p_data->goep_response.opcode, &info) != OBEX_SUCCESS) { + goto error; + } if (p_data->goep_response.opcode == OBEX_OPCODE_CONNECT) { if (info.response_code == (OBEX_RESPONSE_CODE_OK | OBEX_FINAL_BIT_MASK)) { /* obex connect success */ @@ -555,8 +561,13 @@ void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_D p_ccb->max_tx = info.max_packet_length; } BOOLEAN cid_found = false; + UINT8 *pkt_data = (UINT8 *)(p_data->goep_response.pkt + 1) + p_data->goep_response.pkt->offset; + UINT8 *pkt_end = pkt_data + p_data->goep_response.pkt->len; while((header = OBEX_GetNextHeader(p_data->goep_response.pkt, &info)) != NULL) { if (*header == OBEX_HEADER_ID_CONNECTION_ID) { + if (OBEX_GetHeaderLength(header, pkt_end) != 5) { + goto error; + } cid_found = true; memcpy((UINT8 *)(&p_ccb->goep_cid), header + 1, 4); break; @@ -600,6 +611,8 @@ void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_D UINT16 body_data_len = 0; UINT8 *app_param = NULL; UINT16 app_param_len = 0; + UINT8 *pkt_data = (UINT8 *)(p_data->goep_response.pkt + 1) + p_data->goep_response.pkt->offset; + UINT8 *pkt_end = pkt_data + p_data->goep_response.pkt->len; while((header = OBEX_GetNextHeader(p_data->goep_response.pkt, &info)) != NULL) { switch (*header) { @@ -607,7 +620,7 @@ void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_D case OBEX_HEADER_ID_BODY: case OBEX_HEADER_ID_END_OF_BODY: { - UINT16 hi_len = OBEX_GetHeaderLength(header); + UINT16 hi_len = OBEX_GetHeaderLength(header, pkt_end); if (hi_len < 3) { reason = BTA_PBA_CLIENT_BAD_REQUEST; goto error; @@ -627,7 +640,7 @@ void bta_pba_client_response_final(tBTA_PBA_CLIENT_CCB *p_ccb, tBTA_PBA_CLIENT_D } case OBEX_HEADER_ID_APP_PARAM: { - UINT16 hi_len = OBEX_GetHeaderLength(header); + UINT16 hi_len = OBEX_GetHeaderLength(header, pkt_end); if (hi_len < 3) { reason = BTA_PBA_CLIENT_BAD_REQUEST; goto error; diff --git a/components/bt/host/bluedroid/stack/hid/hidd_conn.c b/components/bt/host/bluedroid/stack/hid/hidd_conn.c index 6984bc9a1c0..576d82bdbfb 100644 --- a/components/bt/host/bluedroid/stack/hid/hidd_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidd_conn.c @@ -507,6 +507,11 @@ static void hidd_l2cif_data_ind(uint16_t cid, BT_HDR *p_msg) osi_free(p_msg); return; } + if (p_msg->len < 1) { + HIDD_TRACE_WARNING ("HID-Device Rcvd Empty L2CAP data"); + osi_free(p_msg); + return; + } msg_type = HID_GET_TRANS_FROM_HDR(*p_data); param = HID_GET_PARAM_FROM_HDR(*p_data); if (msg_type == HID_TRANS_DATA && cid == p_hcon->intr_cid) { diff --git a/components/bt/host/bluedroid/stack/hid/hidh_conn.c b/components/bt/host/bluedroid/stack/hid/hidh_conn.c index da880a1ebc3..170bfce7e92 100644 --- a/components/bt/host/bluedroid/stack/hid/hidh_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidh_conn.c @@ -766,6 +766,11 @@ static void hidh_l2cif_data_ind (UINT16 l2cap_cid, BT_HDR *p_msg) return; } + if (p_msg->len < 1) { + HIDH_TRACE_WARNING ("HID-Host Rcvd Empty L2CAP data"); + osi_free (p_msg); + return; + } ttype = HID_GET_TRANS_FROM_HDR(*p_data); param = HID_GET_PARAM_FROM_HDR(*p_data); diff --git a/components/bt/host/bluedroid/stack/include/stack/obex_api.h b/components/bt/host/bluedroid/stack/include/stack/obex_api.h index d22cd33c527..3332b1ac29b 100644 --- a/components/bt/host/bluedroid/stack/include/stack/obex_api.h +++ b/components/bt/host/bluedroid/stack/include/stack/obex_api.h @@ -266,6 +266,6 @@ extern BOOLEAN OBEX_CheckContinueResponse(BT_HDR *pkt); extern UINT8 *OBEX_GetNextHeader(BT_HDR *pkt, tOBEX_PARSE_INFO *info); -extern UINT16 OBEX_GetHeaderLength(UINT8 *header); +extern UINT16 OBEX_GetHeaderLength(UINT8 *header, UINT8 *pkt_end); #endif /* #if (OBEX_INCLUDED == TRUE) */ diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_main.c b/components/bt/host/bluedroid/stack/l2cap/l2c_main.c index b3b5a74d5a6..f59f185c90e 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_main.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_main.c @@ -352,7 +352,7 @@ void l2c_rcv_acl_data (BT_HDR *p_msg) #if (CLASSIC_BT_INCLUDED == TRUE) static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) { - UINT8 *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start; + UINT8 *p_pkt_end, *p_next_cmd, *p_cfg_end, *p_cfg_start, *p_cfg_opt_end; UINT8 cmd_code, cfg_code, cfg_len, id; tL2C_CONN_INFO con_info; tL2CAP_CFG_INFO cfg_info; @@ -526,6 +526,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CMD_CONFIG_REQ: + if (cmd_len < L2CAP_CONFIG_REQ_LEN) { + L2CAP_TRACE_WARNING ("L2CAP - cfg req too short, cmd_len: %d", cmd_len); + break; + } p_cfg_end = p + cmd_len; cfg_rej = FALSE; cfg_rej_len = 0; @@ -539,21 +543,47 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) cfg_info.fcr_present = cfg_info.fcs_present = FALSE; while (p < p_cfg_end) { + if ((p_cfg_end - p) < L2CAP_CFG_OPTION_OVERHEAD) { + cfg_rej = TRUE; + break; + } + STREAM_TO_UINT8 (cfg_code, p); STREAM_TO_UINT8 (cfg_len, p); + if (cfg_len > (p_cfg_end - p)) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } + p_cfg_opt_end = p + cfg_len; switch (cfg_code & 0x7F) { case L2CAP_CFG_TYPE_MTU: + if (cfg_len != L2CAP_CFG_MTU_OPTION_LEN) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } cfg_info.mtu_present = TRUE; STREAM_TO_UINT16 (cfg_info.mtu, p); break; case L2CAP_CFG_TYPE_FLUSH_TOUT: + if (cfg_len != L2CAP_CFG_FLUSH_OPTION_LEN) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } cfg_info.flush_to_present = TRUE; STREAM_TO_UINT16 (cfg_info.flush_to, p); break; case L2CAP_CFG_TYPE_QOS: + if (cfg_len != L2CAP_CFG_QOS_OPTION_LEN) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } cfg_info.qos_present = TRUE; STREAM_TO_UINT8 (cfg_info.qos.qos_flags, p); STREAM_TO_UINT8 (cfg_info.qos.service_type, p); @@ -565,6 +595,11 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CFG_TYPE_FCR: + if (cfg_len != L2CAP_CFG_FCR_OPTION_LEN) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } cfg_info.fcr_present = TRUE; STREAM_TO_UINT8 (cfg_info.fcr.mode, p); STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p); @@ -575,11 +610,21 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CFG_TYPE_FCS: + if (cfg_len != L2CAP_CFG_FCS_OPTION_LEN) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } cfg_info.fcs_present = TRUE; STREAM_TO_UINT8 (cfg_info.fcs, p); break; case L2CAP_CFG_TYPE_EXT_FLOW: + if (cfg_len != L2CAP_CFG_EXT_FLOW_OPTION_LEN) { + p = p_cfg_end; + cfg_rej = TRUE; + break; + } cfg_info.ext_flow_spec_present = TRUE; STREAM_TO_UINT8 (cfg_info.ext_flow_spec.id, p); STREAM_TO_UINT8 (cfg_info.ext_flow_spec.stype, p); @@ -590,17 +635,9 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; default: - /* sanity check option length */ - if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= cmd_len) { - p += cfg_len; - if ((cfg_code & 0x80) == 0) { - cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; - cfg_rej = TRUE; - } - } - /* bad length; force loop exit */ - else { - p = p_cfg_end; + p = p_cfg_opt_end; + if ((cfg_code & 0x80) == 0) { + cfg_rej_len += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; cfg_rej = TRUE; } break; @@ -621,6 +658,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CMD_CONFIG_RSP: + if (cmd_len < L2CAP_CONFIG_RSP_LEN) { + L2CAP_TRACE_WARNING ("L2CAP - cfg rsp too short, cmd_len: %d", cmd_len); + break; + } p_cfg_end = p + cmd_len; STREAM_TO_UINT16 (lcid, p); STREAM_TO_UINT16 (cfg_info.flags, p); @@ -630,21 +671,42 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) cfg_info.fcr_present = cfg_info.fcs_present = FALSE; while (p < p_cfg_end) { + if ((p_cfg_end - p) < L2CAP_CFG_OPTION_OVERHEAD) { + break; + } + STREAM_TO_UINT8 (cfg_code, p); STREAM_TO_UINT8 (cfg_len, p); + if (cfg_len > (p_cfg_end - p)) { + p = p_cfg_end; + break; + } + p_cfg_opt_end = p + cfg_len; switch (cfg_code & 0x7F) { case L2CAP_CFG_TYPE_MTU: + if (cfg_len != L2CAP_CFG_MTU_OPTION_LEN) { + p = p_cfg_end; + break; + } cfg_info.mtu_present = TRUE; STREAM_TO_UINT16 (cfg_info.mtu, p); break; case L2CAP_CFG_TYPE_FLUSH_TOUT: + if (cfg_len != L2CAP_CFG_FLUSH_OPTION_LEN) { + p = p_cfg_end; + break; + } cfg_info.flush_to_present = TRUE; STREAM_TO_UINT16 (cfg_info.flush_to, p); break; case L2CAP_CFG_TYPE_QOS: + if (cfg_len != L2CAP_CFG_QOS_OPTION_LEN) { + p = p_cfg_end; + break; + } cfg_info.qos_present = TRUE; STREAM_TO_UINT8 (cfg_info.qos.qos_flags, p); STREAM_TO_UINT8 (cfg_info.qos.service_type, p); @@ -656,6 +718,10 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CFG_TYPE_FCR: + if (cfg_len != L2CAP_CFG_FCR_OPTION_LEN) { + p = p_cfg_end; + break; + } cfg_info.fcr_present = TRUE; STREAM_TO_UINT8 (cfg_info.fcr.mode, p); STREAM_TO_UINT8 (cfg_info.fcr.tx_win_sz, p); @@ -666,11 +732,19 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) break; case L2CAP_CFG_TYPE_FCS: + if (cfg_len != L2CAP_CFG_FCS_OPTION_LEN) { + p = p_cfg_end; + break; + } cfg_info.fcs_present = TRUE; STREAM_TO_UINT8 (cfg_info.fcs, p); break; case L2CAP_CFG_TYPE_EXT_FLOW: + if (cfg_len != L2CAP_CFG_EXT_FLOW_OPTION_LEN) { + p = p_cfg_end; + break; + } cfg_info.ext_flow_spec_present = TRUE; STREAM_TO_UINT8 (cfg_info.ext_flow_spec.id, p); STREAM_TO_UINT8 (cfg_info.ext_flow_spec.stype, p); @@ -679,6 +753,9 @@ static void process_l2cap_cmd (tL2C_LCB *p_lcb, UINT8 *p, UINT16 pkt_len) STREAM_TO_UINT32 (cfg_info.ext_flow_spec.access_latency, p); STREAM_TO_UINT32 (cfg_info.ext_flow_spec.flush_timeout, p); break; + default: + p = p_cfg_opt_end; + break; } } diff --git a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c index cb3eb797563..2cf6443dccb 100644 --- a/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/host/bluedroid/stack/l2cap/l2c_utils.c @@ -879,7 +879,7 @@ void l2cu_send_peer_config_rsp (tL2C_CCB *p_ccb, tL2CAP_CFG_INFO *p_cfg) void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len, UINT16 rej_len) { BT_HDR *p_buf; - UINT16 len, cfg_len, buf_space, len1; + UINT16 len, cfg_len, buf_space, len1, opt_len; UINT8 *p, *p_hci_len, *p_data_end; UINT8 cfg_code; @@ -936,38 +936,42 @@ void l2cu_send_peer_config_rej (tL2C_CCB *p_ccb, UINT8 *p_data, UINT16 data_len, /* Now, put the rejected options */ p_data_end = p_data + data_len; while (p_data < p_data_end) { + if ((p_data_end - p_data) < L2CAP_CFG_OPTION_OVERHEAD) { + break; + } cfg_code = *p_data; cfg_len = *(p_data + 1); + opt_len = cfg_len + L2CAP_CFG_OPTION_OVERHEAD; + if (opt_len > (UINT16)(p_data_end - p_data)) { + p_data = p_data_end; + break; + } switch (cfg_code & 0x7F) { /* skip known options */ case L2CAP_CFG_TYPE_MTU: case L2CAP_CFG_TYPE_FLUSH_TOUT: case L2CAP_CFG_TYPE_QOS: - p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; + case L2CAP_CFG_TYPE_FCR: + case L2CAP_CFG_TYPE_FCS: + case L2CAP_CFG_TYPE_EXT_FLOW: + p_data += opt_len; break; /* unknown options; copy into rsp if not hints */ default: - /* sanity check option length */ - if ((cfg_len + L2CAP_CFG_OPTION_OVERHEAD) <= data_len) { - if ((cfg_code & 0x80) == 0) { - if (buf_space >= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD)) { - memcpy(p, p_data, cfg_len + L2CAP_CFG_OPTION_OVERHEAD); - p += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; - buf_space -= (cfg_len + L2CAP_CFG_OPTION_OVERHEAD); - } else { - L2CAP_TRACE_WARNING("L2CAP - cfg_rej exceeds allocated buffer"); - p_data = p_data_end; /* force loop exit */ - break; - } + if ((cfg_code & 0x80) == 0) { + if (buf_space >= opt_len) { + memcpy(p, p_data, opt_len); + p += opt_len; + buf_space -= opt_len; + } else { + L2CAP_TRACE_WARNING("L2CAP - cfg_rej exceeds allocated buffer"); + p_data = p_data_end; /* force loop exit */ + break; } - p_data += cfg_len + L2CAP_CFG_OPTION_OVERHEAD; - } - /* bad length; force loop exit */ - else { - p_data = p_data_end; } + p_data += opt_len; break; } } diff --git a/components/bt/host/bluedroid/stack/obex/obex_api.c b/components/bt/host/bluedroid/stack/obex/obex_api.c index bfbe61c6290..f8499f2d171 100644 --- a/components/bt/host/bluedroid/stack/obex/obex_api.c +++ b/components/bt/host/bluedroid/stack/obex/obex_api.c @@ -680,17 +680,29 @@ UINT16 OBEX_ParseResponse(BT_HDR *pkt, UINT8 opcode, tOBEX_PARSE_INFO *info) } UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset; + UINT16 len = pkt->len; + + if (len < 1) { + return OBEX_FAILURE; + } + info->opcode = opcode; info->response_code = *p_data; switch (opcode) { case OBEX_OPCODE_CONNECT: + if (len < 7) { + return OBEX_FAILURE; + } info->obex_version_number = p_data[3]; info->flags = p_data[4]; info->max_packet_length = (p_data[5] << 8) + p_data[6]; info->next_header_pos = 7; break; default: + if (len < 3) { + return OBEX_FAILURE; + } info->next_header_pos = 3; break; } @@ -708,7 +720,7 @@ UINT16 OBEX_ParseResponse(BT_HDR *pkt, UINT8 opcode, tOBEX_PARSE_INFO *info) *******************************************************************************/ BOOLEAN OBEX_CheckFinalBit(BT_HDR *pkt) { - if (pkt == NULL) { + if (pkt == NULL || pkt->len < 1) { return FALSE; } UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset; @@ -726,7 +738,7 @@ BOOLEAN OBEX_CheckFinalBit(BT_HDR *pkt) *******************************************************************************/ BOOLEAN OBEX_CheckContinueResponse(BT_HDR *pkt) { - if (pkt == NULL) { + if (pkt == NULL || pkt->len < 1) { return FALSE; } UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset; @@ -742,15 +754,26 @@ BOOLEAN OBEX_CheckContinueResponse(BT_HDR *pkt) ** Returns header length ** *******************************************************************************/ -UINT16 OBEX_GetHeaderLength(UINT8 *header) +UINT16 OBEX_GetHeaderLength(UINT8 *header, UINT8 *pkt_end) { + if (header == NULL || pkt_end == NULL || header >= pkt_end) { + return 0; + } + + UINT16 remaining_len = (UINT16)(pkt_end - header); UINT16 header_len = 0; UINT8 header_id = *header; + switch (header_id & OBEX_HEADER_ID_U2B_MASK) { case OBEX_HEADER_ID_U2B_TYPE1: case OBEX_HEADER_ID_U2B_TYPE2: - header_len = (header[1] << 8) + header[2]; + if (remaining_len >= 3) { + header_len = (header[1] << 8) + header[2]; + } + if (header_len < 3) { + header_len = 0; + } break; case OBEX_HEADER_ID_U2B_TYPE3: header_len = 2; @@ -762,6 +785,11 @@ UINT16 OBEX_GetHeaderLength(UINT8 *header) /* unreachable */ break; } + + if (header_len > remaining_len) { + return 0; + } + return header_len; } @@ -785,7 +813,11 @@ UINT8 *OBEX_GetNextHeader(BT_HDR *pkt, tOBEX_PARSE_INFO *info) } UINT8 *p_data = (UINT8 *)(pkt + 1) + pkt->offset; UINT8 *header = p_data + info->next_header_pos; - UINT16 header_len = OBEX_GetHeaderLength(header); + UINT8 *pkt_end = p_data + pkt->len; + UINT16 header_len = OBEX_GetHeaderLength(header, pkt_end); + if (header_len == 0) { + return NULL; + } info->next_header_pos += header_len; return header; } diff --git a/components/bt/host/bluedroid/stack/smp/smp_keys.c b/components/bt/host/bluedroid/stack/smp/smp_keys.c index 99cce9b401f..8924b2f90e8 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_keys.c +++ b/components/bt/host/bluedroid/stack/smp/smp_keys.c @@ -2315,11 +2315,8 @@ BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb) SMP_TRACE_ERROR("%s failed", __func__); } else { UINT8 link_key_type; - if (btm_cb.security_mode == BTM_SEC_MODE_SC) { - /* Secure Connections Only Mode */ - link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; - } else if (controller_get_interface()->supports_secure_connections()) { - /* both transports are SC capable */ + if ((btm_cb.security_mode == BTM_SEC_MODE_SC) || + (controller_get_interface()->supports_secure_connections())) { if (p_cb->sec_level == SMP_SEC_AUTHENTICATED) { link_key_type = BTM_LKEY_TYPE_AUTH_COMB_P_256; } else { diff --git a/components/bt/host/bluedroid/stack/smp/smp_l2c.c b/components/bt/host/bluedroid/stack/smp/smp_l2c.c index 9b019ae73fa..d33e010d850 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/host/bluedroid/stack/smp/smp_l2c.c @@ -335,13 +335,15 @@ static void smp_br_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) return; } + /* Validate command length to prevent out-of-bounds read in handler functions */ + if (p_buf->len != smp_cmd_size_per_spec[cmd]) { + SMP_TRACE_WARNING( "Ignore received command 0x%02x with invalid length %d", cmd, p_buf->len); + osi_free(p_buf); + return; + } + /* reject the pairing request if there is an on-going SMP pairing */ if (SMP_OPCODE_PAIRING_REQ == cmd) { - if (p_buf->len != smp_cmd_size_per_spec[cmd]) { - SMP_TRACE_WARNING( "Ignore received command 0x%02x with invalid length %d", cmd, p_buf->len); - osi_free(p_buf); - return; - } if ((p_cb->state == SMP_STATE_IDLE) && (p_cb->br_state == SMP_BR_STATE_IDLE)) { p_cb->role = HCI_ROLE_SLAVE; p_cb->smp_over_br = TRUE;