mirror of
https://github.com/espressif/esp-idf.git
synced 2026-08-18 06:35:35 +03:00
fix(ble_mesh): fix DFD client message parsing and encoding bugs
Fix multiple wire-format and robustness issues in the DFD client (dfd_cli.c): - handle_capabilities: read oob_retrieval_supported as u8 instead of le32. The server encodes a single byte; le32 over-consumed 3 bytes of the URL scheme list and could over-read the buffer. - handle_upload_status: extract upload_progress from bits 0-6 (& 0x7F) and upload_type from bit 7 (>> 7), matching the server encoding (progress | BIT(7)). The previous >>1 / &0x01 returned wrong values, mis-classified in-band vs OOB, and falsely rejected valid OOB messages with high progress. - handle_dfd_status: correct the transfer-mode byte layout to trans_mode bits 0-1, update_policy bit 2, RFU bits 3-7 (previously read bits 6-7 / 5), and fix the RFU mask to 0xF8. Now matches the struct bitfield definition and the DFD server. - handle_dfd_status: report status+phase and return early when buf->len == 0 (IDLE phase) instead of pulling 10 absent bytes. - bt_mesh_dfd_cli_distribution_start: encode trans_mode/update_policy into bits 0-2 so the server decodes them correctly. - handle_receiver_list: validate buf->len >= entries_cnt * 5 before the loop, and handle entries_cnt == 0 without relying on calloc(0). - handle_receiver_status: pass the status value (not the whole union) to the %d log format, fixing undefined behavior. - dfd_client_recv_status: drop the dead BLE_MESH_DFD_OP_CAPABILITIES_GET case (a client-send opcode) from the receive switch. - bt_mesh_dfd_cli_receivers_add: widen msg_length to uint32_t to avoid uint16_t overflow that bypassed the PDU size guard; add a NULL check for the receivers array. - bt_mesh_dfd_cli_distribution_upload_oob_start: return -EINVAL instead of -1 for consistency with the rest of the file.
This commit is contained in:
@@ -86,7 +86,6 @@ static void dfd_client_recv_status(struct bt_mesh_model *model,
|
||||
} else {
|
||||
switch (ctx->recv_op) {
|
||||
case BLE_MESH_DFD_OP_RECEIVERS_STATUS:
|
||||
case BLE_MESH_DFD_OP_CAPABILITIES_GET:
|
||||
case BLE_MESH_DFD_OP_RECEIVERS_LIST:
|
||||
case BLE_MESH_DFD_OP_CAPABILITIES_STATUS:
|
||||
case BLE_MESH_DFD_OP_STATUS:
|
||||
@@ -122,7 +121,7 @@ static void handle_receiver_status(struct bt_mesh_model *model,
|
||||
}
|
||||
|
||||
if (status.receiver_status.status != BLE_MESH_DFD_SUCCESS) {
|
||||
BT_ERR("StusErr:%d", status);
|
||||
BT_ERR("StusErr:%d", status.receiver_status.status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,13 +148,23 @@ static void handle_receiver_list(struct bt_mesh_model *model,
|
||||
}
|
||||
|
||||
status.receiver_list.first_index = net_buf_simple_pull_le16(buf);
|
||||
status.receiver_list.entries = bt_mesh_calloc(status.receiver_list.entries_cnt * sizeof(target_node_entry_t));
|
||||
|
||||
if (status.receiver_list.entries == NULL) {
|
||||
BT_ERR("MemAllocFailedForSz:%d",status.receiver_list.entries_cnt * sizeof(target_node_entry_t));
|
||||
/* Each entry is 4 bytes (packed target info) + 1 byte (fwidx) = 5 bytes. */
|
||||
if (buf->len < (uint32_t)status.receiver_list.entries_cnt * 5u) {
|
||||
BT_ERR("InvRcvListLen:cnt=%d,buf=%d", status.receiver_list.entries_cnt, buf->len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (status.receiver_list.entries_cnt == 0) {
|
||||
status.receiver_list.entries = NULL;
|
||||
} else {
|
||||
status.receiver_list.entries = bt_mesh_calloc(status.receiver_list.entries_cnt * sizeof(target_node_entry_t));
|
||||
if (status.receiver_list.entries == NULL) {
|
||||
BT_ERR("MemAllocFailedForSz:%zu",status.receiver_list.entries_cnt * sizeof(target_node_entry_t));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < status.receiver_list.entries_cnt; i++) {
|
||||
target_info = net_buf_simple_pull_le32(buf);
|
||||
status.receiver_list.entries[i].addr = TARGET_ADDR(target_info);
|
||||
@@ -182,7 +191,7 @@ static void handle_capabilities(struct bt_mesh_model *model,
|
||||
status.dist_caps.max_fw_sz = net_buf_simple_pull_le32(buf);
|
||||
status.dist_caps.max_upload_space = net_buf_simple_pull_le32(buf);
|
||||
status.dist_caps.remaining_upload_space = net_buf_simple_pull_le32(buf);
|
||||
status.dist_caps.oob_retrieval_supported = net_buf_simple_pull_le32(buf);
|
||||
status.dist_caps.oob_retrieval_supported = net_buf_simple_pull_u8(buf);
|
||||
if (buf->len) {
|
||||
status.dist_caps.supported_url_scheme_names = &url_scheme_names;
|
||||
net_buf_simple_init_with_data(status.dist_caps.supported_url_scheme_names, buf->data, buf->len);
|
||||
@@ -201,7 +210,13 @@ static void handle_dfd_status(struct bt_mesh_model *model,
|
||||
|
||||
status.dist_status.status = net_buf_simple_pull_u8(buf);
|
||||
status.dist_status.dist_phase = net_buf_simple_pull_u8(buf);
|
||||
if (buf->len != 0 && buf->len != 10) {
|
||||
if (buf->len == 0) {
|
||||
/* Only Status and Distribution Phase are present (e.g. IDLE phase);
|
||||
* the optional fields are not part of the message. */
|
||||
dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_status));
|
||||
return;
|
||||
}
|
||||
if (buf->len != 10) {
|
||||
BT_ERR("Invalid data");
|
||||
return;
|
||||
}
|
||||
@@ -211,13 +226,14 @@ static void handle_dfd_status(struct bt_mesh_model *model,
|
||||
status.dist_status.timeout_base = net_buf_simple_pull_le16(buf);
|
||||
|
||||
trans_mode_policy = net_buf_simple_pull_u8(buf);
|
||||
if ((trans_mode_policy & ~(BIT6 - 1)) != 0) {
|
||||
if ((trans_mode_policy & 0xF8) != 0) {
|
||||
BT_ERR("RFU should be zero");
|
||||
return;
|
||||
}
|
||||
status.dist_status.trans_mode = trans_mode_policy >> 6;
|
||||
status.dist_status.update_policy = (trans_mode_policy >> 5) & 0x01;
|
||||
status.dist_status.RFU = trans_mode_policy & 0x1f;
|
||||
/* trans_mode: bits 0-1, update_policy: bit 2, RFU: bits 3-7 */
|
||||
status.dist_status.trans_mode = trans_mode_policy & 0x03;
|
||||
status.dist_status.update_policy = (trans_mode_policy >> 2) & 0x01;
|
||||
status.dist_status.RFU = (trans_mode_policy >> 3) & 0x1f;
|
||||
status.dist_status.fw_idx = net_buf_simple_pull_le16(buf);
|
||||
dfd_client_recv_status(model, ctx, &status, sizeof(status.dist_status));
|
||||
return;
|
||||
@@ -240,7 +256,7 @@ static void handle_upload_status(struct bt_mesh_model *model,
|
||||
}
|
||||
|
||||
progress_type = net_buf_simple_pull_u8(buf);
|
||||
status.upload_status.upload_progress = progress_type>>1;
|
||||
status.upload_status.upload_progress = progress_type & 0x7F;
|
||||
|
||||
if (status.upload_status.upload_progress >= UPLOAD_PROGRESS_UNSET) {
|
||||
BT_ERR("Invalid upload progress");
|
||||
@@ -252,7 +268,7 @@ static void handle_upload_status(struct bt_mesh_model *model,
|
||||
return;
|
||||
}
|
||||
|
||||
status.upload_status.upload_type = progress_type & 0x01;
|
||||
status.upload_status.upload_type = (progress_type >> 7) & 0x01;
|
||||
if (status.upload_status.upload_type == UPLOAD_IN_BAND) {
|
||||
status.upload_status.fwid = &buf_cache;
|
||||
net_buf_simple_init_with_data(status.upload_status.fwid, buf->data, buf->len);
|
||||
@@ -300,7 +316,7 @@ const struct bt_mesh_model_op _bt_mesh_dfd_cli_op[] = {
|
||||
|
||||
int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, dfd_cli_receiver_entry_t *receivers, uint16_t receivers_cnt)
|
||||
{
|
||||
uint16_t msg_length = 2;
|
||||
uint32_t msg_length = 2;
|
||||
struct net_buf_simple *msg = NULL;
|
||||
dfd_cli_receiver_entry_t *entry = NULL;
|
||||
int err = 0;
|
||||
@@ -310,8 +326,13 @@ int bt_mesh_dfd_cli_receivers_add(bt_mesh_client_common_param_t *param, dfd_cli_
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (receivers == NULL && receivers_cnt) {
|
||||
BT_ERR("Invalid receivers");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_INFO("AddedValidCnt:%d", receivers_cnt);
|
||||
msg_length += (receivers_cnt * 3);
|
||||
msg_length += (uint32_t)receivers_cnt * 3;
|
||||
|
||||
/* needs to confirm long or short mic */
|
||||
if (msg_length > BLE_MESH_MAX_PDU_LEN_WITH_SMIC) {
|
||||
@@ -404,7 +425,7 @@ int bt_mesh_dfd_cli_distribution_start(bt_mesh_client_common_param_t *param,
|
||||
net_buf_simple_add_le16(&msg, start->app_idx);
|
||||
net_buf_simple_add_u8(&msg, start->ttl);
|
||||
net_buf_simple_add_le16(&msg, start->timeout_base);
|
||||
net_buf_simple_add_u8(&msg, ((start->trans_mode) << 6) | ((start->update_policy) << 5));
|
||||
net_buf_simple_add_u8(&msg, ((start->trans_mode) & 0x03) | (((start->update_policy) & 0x01) << 2));
|
||||
net_buf_simple_add_le16(&msg, start->fw_idx);
|
||||
|
||||
if (start->is_va) {
|
||||
@@ -515,17 +536,17 @@ int bt_mesh_dfd_cli_distribution_upload_oob_start(bt_mesh_client_common_param_t
|
||||
|
||||
if (!param || !start) {
|
||||
BT_ERR("Invalid param");
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!start->url) {
|
||||
BT_ERR("Null url info");
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!start->fwid) {
|
||||
BT_ERR("Invalid firmware id");
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg_length += (1 + start->url->len + start->fwid->len);
|
||||
|
||||
Reference in New Issue
Block a user