mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-14 01:27:41 +00:00
avrcp: avoid out of bound reads in target and controller
This commit is contained in:
parent
39ac97114d
commit
99702381fb
@ -87,9 +87,12 @@ static int avrcp_controller_supports_browsing(uint16_t controller_supported_feat
|
||||
return controller_supported_features & AVRCP_FEATURE_MASK_BROWSING;
|
||||
}
|
||||
|
||||
static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id, avrcp_command_type_t ctype, const uint8_t * payload){
|
||||
static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid, avrcp_notification_event_id_t event_id,
|
||||
avrcp_command_type_t ctype, const uint8_t *payload,
|
||||
uint16_t size) {
|
||||
switch (event_id){
|
||||
case AVRCP_NOTIFICATION_EVENT_PLAYBACK_POS_CHANGED:{
|
||||
if (size < 4) break;
|
||||
uint32_t song_position = big_endian_read_32(payload, 0);
|
||||
uint16_t offset = 0;
|
||||
uint8_t event[10];
|
||||
@ -105,6 +108,7 @@ static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid,
|
||||
break;
|
||||
}
|
||||
case AVRCP_NOTIFICATION_EVENT_PLAYBACK_STATUS_CHANGED:{
|
||||
if (size < 1) break;
|
||||
uint16_t offset = 0;
|
||||
uint8_t event[7];
|
||||
event[offset++] = HCI_EVENT_AVRCP_META;
|
||||
@ -154,6 +158,7 @@ static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid,
|
||||
break;
|
||||
}
|
||||
case AVRCP_NOTIFICATION_EVENT_VOLUME_CHANGED:{
|
||||
if (size < 1) break;
|
||||
uint16_t offset = 0;
|
||||
uint8_t event[7];
|
||||
event[offset++] = HCI_EVENT_AVRCP_META;
|
||||
@ -167,6 +172,7 @@ static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid,
|
||||
break;
|
||||
}
|
||||
case AVRCP_NOTIFICATION_EVENT_UIDS_CHANGED:{
|
||||
if (size < 2) break;
|
||||
uint8_t event[8];
|
||||
uint16_t offset = 0;
|
||||
uint16_t uuid = big_endian_read_16(payload, 0);
|
||||
@ -207,6 +213,7 @@ static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid,
|
||||
break;
|
||||
}
|
||||
case AVRCP_NOTIFICATION_EVENT_BATT_STATUS_CHANGED:{
|
||||
if (size < 1) break;
|
||||
uint16_t offset = 0;
|
||||
uint8_t event[7];
|
||||
event[offset++] = HCI_EVENT_AVRCP_META;
|
||||
@ -221,6 +228,7 @@ static void avrcp_controller_emit_notification_for_event_id(uint16_t avrcp_cid,
|
||||
}
|
||||
|
||||
case AVRCP_NOTIFICATION_EVENT_SYSTEM_STATUS_CHANGED:{
|
||||
if (size < 1) break;
|
||||
uint16_t offset = 0;
|
||||
uint8_t event[7];
|
||||
event[offset++] = HCI_EVENT_AVRCP_META;
|
||||
@ -644,7 +652,9 @@ static uint8_t avrcp_controller_request_continue_response(avrcp_connection_t * c
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static void avrcp_controller_handle_notification(avrcp_connection_t * connection, avrcp_command_type_t ctype, uint8_t * payload){
|
||||
static void
|
||||
avrcp_controller_handle_notification(avrcp_connection_t *connection, avrcp_command_type_t ctype, uint8_t *payload, uint16_t size) {
|
||||
if (size < 1) return;
|
||||
uint16_t pos = 0;
|
||||
avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) payload[pos++];
|
||||
uint16_t event_mask = (1 << event_id);
|
||||
@ -671,14 +681,13 @@ static void avrcp_controller_handle_notification(avrcp_connection_t * connection
|
||||
connection->notifications_to_deregister &= reset_event_mask;
|
||||
break;
|
||||
}
|
||||
|
||||
avrcp_controller_emit_notification_for_event_id(connection->avrcp_cid, event_id, ctype, payload+pos);
|
||||
|
||||
avrcp_controller_emit_notification_for_event_id(connection->avrcp_cid, event_id, ctype, payload + pos, size - pos);
|
||||
}
|
||||
|
||||
static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
|
||||
if (size < 6u) return;
|
||||
|
||||
uint16_t pos = 3;
|
||||
uint8_t pdu_id;
|
||||
uint8_t vendor_dependent_packet_type;
|
||||
|
||||
@ -695,7 +704,8 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
log_info("Fragmentation is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint16_t pos = 3;
|
||||
avrcp_command_type_t ctype = (avrcp_command_type_t) packet[pos++];
|
||||
|
||||
#ifdef ENABLE_LOG_INFO
|
||||
@ -739,6 +749,9 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
break;
|
||||
}
|
||||
case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
|
||||
|
||||
if ((size - pos) < 7) return;
|
||||
|
||||
// Company ID (3)
|
||||
pos += 3;
|
||||
pdu_id = packet[pos++];
|
||||
@ -747,14 +760,11 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
pos += 2;
|
||||
log_info("operands length %d, remaining size %d", param_length, size - pos);
|
||||
|
||||
if ((size - pos) < param_length) {
|
||||
log_error("Wrong packet size %d < %d", size - pos, param_length);
|
||||
return;
|
||||
};
|
||||
if ((size - pos) < param_length) return;
|
||||
|
||||
// handle asynchronous notifications, without changing state
|
||||
if (pdu_id == AVRCP_PDU_ID_REGISTER_NOTIFICATION){
|
||||
avrcp_controller_handle_notification(connection, ctype, packet+pos);
|
||||
avrcp_controller_handle_notification(connection, ctype, packet + pos, size - pos);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -955,6 +965,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
}
|
||||
break;
|
||||
case AVRCP_CMD_OPCODE_PASS_THROUGH:{
|
||||
if ((size - pos) < 1) return;
|
||||
uint8_t operation_id = packet[pos++];
|
||||
switch (connection->state){
|
||||
case AVCTP_W2_RECEIVE_PRESS_RESPONSE:
|
||||
|
@ -789,9 +789,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
avrcp_subunit_id_t subunit_id = (avrcp_subunit_id_t) (packet[4] & 0x07);
|
||||
|
||||
avrcp_command_opcode_t opcode = (avrcp_command_opcode_t) avrcp_cmd_opcode(packet,size);
|
||||
uint8_t * company_id = avrcp_get_company_id(packet, size);
|
||||
uint8_t * pdu = avrcp_get_pdu(packet, size);
|
||||
|
||||
|
||||
int pos = 4;
|
||||
uint16_t length;
|
||||
avrcp_pdu_id_t pdu_id;
|
||||
@ -802,11 +800,13 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
avrcp_target_unit_info(connection);
|
||||
break;
|
||||
case AVRCP_CMD_OPCODE_SUBUNIT_INFO:{
|
||||
if ((size - pos) < 3) return;
|
||||
uint8_t offset = 4 * (packet[pos+2]>>4);
|
||||
avrcp_target_subunit_info(connection, offset);
|
||||
break;
|
||||
}
|
||||
case AVRCP_CMD_OPCODE_PASS_THROUGH:{
|
||||
if (size < 9) return;
|
||||
log_info("AVRCP_OPERATION_ID 0x%02x, operands length %d, operand %d", packet[6], packet[7], packet[8]);
|
||||
avrcp_operation_id_t operation_id = (avrcp_operation_id_t) packet[6];
|
||||
|
||||
@ -850,17 +850,27 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
}
|
||||
|
||||
case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
|
||||
pdu_id = (avrcp_pdu_id_t) pdu[0];
|
||||
// 1 - reserved
|
||||
// 2-3 param length,
|
||||
length = big_endian_read_16(pdu, 2);
|
||||
(void)memcpy(connection->cmd_operands, company_id, 3);
|
||||
|
||||
if (size < 13) return;
|
||||
|
||||
// pos = 6 - company id
|
||||
(void)memcpy(connection->cmd_operands, &packet[pos], 3);
|
||||
connection->cmd_operands_length = 3;
|
||||
pos += 3;
|
||||
// pos = 9
|
||||
pdu_id = (avrcp_pdu_id_t) packet[pos++];
|
||||
// 1 - reserved
|
||||
pos++;
|
||||
// 2-3 param length,
|
||||
length = big_endian_read_16(packet, pos);
|
||||
pos += 2;
|
||||
// pos = 13
|
||||
switch (pdu_id){
|
||||
case AVRCP_PDU_ID_SET_ADDRESSED_PLAYER:{
|
||||
if ((pos + 2) > size) return;
|
||||
bool ok = length == 4;
|
||||
if (avrcp_target_context.set_addressed_player_callback != NULL){
|
||||
uint16_t player_id = big_endian_read_16(pdu, 4);
|
||||
uint16_t player_id = big_endian_read_16(packet, pos);
|
||||
ok = avrcp_target_context.set_addressed_player_callback(player_id);
|
||||
}
|
||||
if (ok){
|
||||
@ -871,7 +881,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
break;
|
||||
}
|
||||
case AVRCP_PDU_ID_GET_CAPABILITIES:{
|
||||
avrcp_capability_id_t capability_id = (avrcp_capability_id_t) pdu[pos];
|
||||
avrcp_capability_id_t capability_id = (avrcp_capability_id_t) packet[pos];
|
||||
switch (capability_id){
|
||||
case AVRCP_CAPABILITY_ID_EVENT:
|
||||
avrcp_target_emit_respond_vendor_dependent_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_EVENT_IDS_QUERY);
|
||||
@ -889,12 +899,14 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
avrcp_target_emit_respond_vendor_dependent_query(avrcp_target_context.avrcp_callback, connection->avrcp_cid, AVRCP_SUBEVENT_PLAY_STATUS_QUERY);
|
||||
break;
|
||||
case AVRCP_PDU_ID_REQUEST_ABORT_CONTINUING_RESPONSE:
|
||||
connection->cmd_operands[0] = pdu[4];
|
||||
if ((pos + 1) > size) return;
|
||||
connection->cmd_operands[0] = packet[pos];
|
||||
connection->abort_continue_response = 1;
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
break;
|
||||
case AVRCP_PDU_ID_REQUEST_CONTINUING_RESPONSE:
|
||||
if (pdu[4] != AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES){
|
||||
if ((pos + 1) > size) return;
|
||||
if (packet[pos] != AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES){
|
||||
avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_COMMAND);
|
||||
return;
|
||||
}
|
||||
@ -902,22 +914,24 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
|
||||
break;
|
||||
case AVRCP_PDU_ID_GET_ELEMENT_ATTRIBUTES:{
|
||||
if ((pos + 9) > size) return;
|
||||
uint8_t play_identifier[8];
|
||||
memset(play_identifier, 0, 8);
|
||||
if (memcmp(pdu+pos, play_identifier, 8) != 0) {
|
||||
if (memcmp(&packet[pos], play_identifier, 8) != 0) {
|
||||
avrcp_target_response_reject(connection, subunit_type, subunit_id, opcode, pdu_id, AVRCP_STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
pos += 8;
|
||||
uint8_t attribute_count = pdu[pos++];
|
||||
uint8_t attribute_count = packet[pos++];
|
||||
connection->next_attr_id = AVRCP_MEDIA_ATTR_NONE;
|
||||
if (!attribute_count){
|
||||
connection->now_playing_info_attr_bitmap = 0xFE;
|
||||
} else {
|
||||
int i;
|
||||
connection->now_playing_info_attr_bitmap = 0;
|
||||
if ((pos + attribute_count * 2) > size) return;
|
||||
for (i=0; i < attribute_count; i++){
|
||||
uint16_t attr_id = big_endian_read_16(pdu, pos);
|
||||
uint16_t attr_id = big_endian_read_16(packet, pos);
|
||||
pos += 2;
|
||||
connection->now_playing_info_attr_bitmap |= (1 << attr_id);
|
||||
}
|
||||
@ -927,10 +941,8 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
break;
|
||||
}
|
||||
case AVRCP_PDU_ID_REGISTER_NOTIFICATION:{
|
||||
// 0 - pdu id
|
||||
// 1 - reserved
|
||||
// 2-3 param length
|
||||
avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) pdu[4];
|
||||
if ((pos + 1) > size) return;
|
||||
avrcp_notification_event_id_t event_id = (avrcp_notification_event_id_t) packet[pos];
|
||||
uint16_t event_mask = (1 << event_id);
|
||||
avrcp_target_set_transaction_label_for_notification(connection, event_id, connection->transaction_id);
|
||||
|
||||
@ -986,7 +998,8 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t absolute_volume = pdu[4];
|
||||
if ((pos + 1) > size) return;
|
||||
uint8_t absolute_volume = packet[pos];
|
||||
if (absolute_volume < 0x80){
|
||||
connection->volume_percentage = absolute_volume;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user