Bluetooth: LE: BAP: Check buf len before using it

Check whether the length of buf is consistent with the valid data
received for op code BT_BAP_BASS_OP_ADD_SRC and BT_BAP_BASS_OP_MOD_SRC.

If the length of buf is inconsistent with the valid data received, the
response is error code BT_ATT_ERR_WRITE_REQ_REJECTED instead of other
errors.

Signed-off-by: Lyle Zhu <lyle.zhu@nxp.com>
This commit is contained in:
Lyle Zhu 2024-12-20 20:10:04 +08:00 committed by Benjamin Cabé
commit 132a24d21c

View file

@ -494,6 +494,8 @@ static int scan_delegator_add_source(struct bt_conn *conn,
uint32_t aggregated_bis_syncs = 0;
uint32_t broadcast_id;
bool bis_sync_requested;
uint16_t total_len;
struct bt_bap_bass_cp_add_src *add_src;
/* subtract 1 as the opcode has already been pulled */
if (buf->len < sizeof(struct bt_bap_bass_cp_add_src) - 1) {
@ -501,6 +503,34 @@ static int scan_delegator_add_source(struct bt_conn *conn,
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
add_src = (void *)(buf->data - 1);
total_len = sizeof(struct bt_bap_bass_cp_add_src) - 1;
for (int i = 0; i < add_src->num_subgroups; i++) {
struct bt_bap_bass_cp_subgroup *subgroup;
uint16_t index = total_len;
total_len += sizeof(struct bt_bap_bass_cp_subgroup);
if (total_len > buf->len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
subgroup = (void *)&buf->data[index];
total_len += subgroup->metadata_len;
if (total_len > buf->len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
}
if (total_len != buf->len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
internal_state = get_free_recv_state();
if (internal_state == NULL) {
LOG_DBG("Could not get free receive state");
@ -558,11 +588,6 @@ static int scan_delegator_add_source(struct bt_conn *conn,
struct bt_bap_bass_subgroup *subgroup = &state->subgroups[i];
uint8_t *metadata;
if (buf->len < (sizeof(subgroup->bis_sync) + sizeof(subgroup->metadata_len))) {
LOG_DBG("Invalid length %u", buf->size);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf);
if (internal_state->requested_bis_sync[i] &&
@ -596,13 +621,6 @@ static int scan_delegator_add_source(struct bt_conn *conn,
subgroup->metadata_len = net_buf_simple_pull_u8(buf);
if (buf->len < subgroup->metadata_len) {
LOG_DBG("Invalid length %u", buf->size);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
if (subgroup->metadata_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
LOG_WRN("Metadata too long %u/%u", subgroup->metadata_len,
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
@ -615,11 +633,6 @@ static int scan_delegator_add_source(struct bt_conn *conn,
subgroup->metadata_len);
}
if (buf->len != 0) {
LOG_DBG("Invalid length %u", buf->size);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
/* The active flag shall be set before any application callbacks, so that any calls for the
* receive state can be processed
*/
@ -676,6 +689,8 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
uint8_t pa_sync;
uint32_t aggregated_bis_syncs = 0;
bool bis_sync_change_requested;
uint16_t total_len;
struct bt_bap_bass_cp_mod_src *mod_src;
/* subtract 1 as the opcode has already been pulled */
if (buf->len < sizeof(struct bt_bap_bass_cp_mod_src) - 1) {
@ -684,6 +699,34 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
mod_src = (void *)(buf->data - 1);
total_len = sizeof(struct bt_bap_bass_cp_mod_src) - 1;
for (int i = 0; i < mod_src->num_subgroups; i++) {
struct bt_bap_bass_cp_subgroup *subgroup;
uint16_t index = total_len;
total_len += sizeof(struct bt_bap_bass_cp_subgroup);
if (total_len > buf->len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
subgroup = (void *)&buf->data[index];
total_len += subgroup->metadata_len;
if (total_len > buf->len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
}
if (total_len != buf->len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
src_id = net_buf_simple_pull_u8(buf);
internal_state = bass_lookup_src_id(src_id);
@ -718,11 +761,6 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
uint32_t old_bis_sync_req;
uint8_t *metadata;
if (buf->len < (sizeof(subgroup->bis_sync) + sizeof(subgroup->metadata_len))) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
old_bis_sync_req = internal_state->requested_bis_sync[i];
internal_state->requested_bis_sync[i] = net_buf_simple_pull_le32(buf);
@ -754,11 +792,6 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
subgroup->metadata_len = net_buf_simple_pull_u8(buf);
if (buf->len < subgroup->metadata_len) {
LOG_DBG("Invalid length %u", buf->len);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
if (subgroup->metadata_len > CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE) {
LOG_WRN("Metadata too long %u/%u", subgroup->metadata_len,
CONFIG_BT_AUDIO_CODEC_CFG_MAX_METADATA_SIZE);
@ -771,12 +804,6 @@ static int scan_delegator_mod_src(struct bt_conn *conn,
subgroup->metadata_len);
}
if (buf->len != 0) {
LOG_DBG("Invalid length %u", buf->size);
return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
}
/* All input has been validated; update receive state and check for changes */
state = &internal_state->state;