fix(bt/bluedroid): added buffer length check for OBEX APIs

This commit is contained in:
Jin Cheng
2026-05-29 14:25:11 +08:00
parent 674c4871f7
commit 8cd04abc12
4 changed files with 78 additions and 16 deletions

View File

@@ -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 */

View File

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

View File

@@ -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) */

View File

@@ -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;
}