From 23001a291eacd44c98fe094c0c9cdff3775e4091 Mon Sep 17 00:00:00 2001 From: Luo Xu Date: Mon, 9 Feb 2026 17:43:25 +0800 Subject: [PATCH] fix(ble_mesh): added internal buffer to store dfu targets The protocol may still receive DFU-related packets from the network (such as forwarded or retransmitted ones) after DFU ends, while the user might release the targets immediately after DFU completion. However, since the list head is not empty, the protocol could access already-freed memory when iterating through the targets. (cherry picked from commit 8c8b43f564470c3a184a34d6bbcb41ff48113606) Co-authored-by: luoxu --- .../api/models/esp_ble_mesh_dfu_model_api.c | 3 +- .../v1.1/btc/btc_ble_mesh_dfu_model.c | 7 +- components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c | 88 ++++++++++++++++++- .../v1.1/include/mesh_v1.1/dfu/dfu_cli.h | 3 + 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c index 84110f8ade4..09cfd23da31 100644 --- a/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c +++ b/components/bt/esp_ble_mesh/v1.1/api/models/esp_ble_mesh_dfu_model_api.c @@ -73,7 +73,8 @@ esp_err_t esp_ble_mesh_dfu_cli_img_send(esp_ble_mesh_dfu_cli_t *cli, arg.send_arg.xfer = xfer; return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_dfu_client_args_t), - NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); + btc_ble_mesh_dfu_client_arg_deep_copy, + btc_ble_mesh_dfu_client_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL); } uint8_t esp_ble_mesh_dfu_cli_progress(esp_ble_mesh_dfu_cli_t *cli) diff --git a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c index b6fe3ecdbd5..d23497ef2f3 100644 --- a/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c +++ b/components/bt/esp_ble_mesh/v1.1/btc/btc_ble_mesh_dfu_model.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -81,6 +81,11 @@ void btc_ble_mesh_dfu_client_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p } break; } + case BTC_BLE_MESH_ACT_DFU_CLIENT_IMG_SEND: + /* That will be freed when dfu completed or failed not on btc deep free */ + dst->send_arg.inputs =(struct esp_ble_mesh_blob_cli_inputs *) + dfu_targets_alloc((struct bt_mesh_blob_cli_inputs *)src->send_arg.inputs); + break; default: BT_DBG("%s, Unknown act %d", __func__, msg->act); break; diff --git a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c index bee0ecacdd7..78c7219f04c 100644 --- a/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c +++ b/components/bt/esp_ble_mesh/v1.1/dfu/dfu_cli.c @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: 2020 Nordic Semiconductor ASA - * SPDX-FileContributor: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -64,6 +64,83 @@ static struct { sys_slist_t list; } dfu_req_list; +static struct bt_mesh_blob_cli_inputs cur_targets = {0}; + +/** + * inputs list must point to a list of bt_mesh_dfu_target nodes. + * That was required by dfu api + */ +void dfu_targets_free(void) +{ + sys_snode_t *n, *sn; + struct bt_mesh_dfu_target *target; + struct bt_mesh_blob_cli_inputs *inputs = &cur_targets; + + if (cur_targets.targets.head == NULL) { + return; + } + + SYS_SLIST_FOR_EACH_NODE_SAFE(&inputs->targets, n, sn) { + target = (struct bt_mesh_dfu_target *)n; + if (target->blob.pull) { + bt_mesh_free(target->blob.pull); + } + bt_mesh_free(target); + } + + inputs->app_idx = 0; + inputs->group = 0; + inputs->ttl = 0; + inputs->timeout_base = 0; + + sys_slist_init(&inputs->targets); +} + +struct bt_mesh_blob_cli_inputs *dfu_targets_alloc(struct bt_mesh_blob_cli_inputs *src) +{ + sys_snode_t *node; + struct bt_mesh_dfu_target *target_src = NULL; + struct bt_mesh_dfu_target *target_dst = NULL; + struct bt_mesh_blob_cli_inputs *dst = &cur_targets; + + if (cur_targets.targets.head != NULL || + cur_targets.targets.tail != NULL) { + BT_WARN("DFU targets busy"); + return NULL; + } + + dst->app_idx = src->app_idx; + dst->group = src->group; + dst->ttl = src->ttl; + dst->timeout_base = src->timeout_base; + + sys_slist_init(&dst->targets); + + SYS_SLIST_FOR_EACH_NODE(&src->targets, node) { + target_src = (struct bt_mesh_dfu_target *)node; + target_dst = bt_mesh_calloc(sizeof(struct bt_mesh_dfu_target)); + if (!target_dst) { + dfu_targets_free(); + return NULL; + } + memcpy(target_dst, target_src, sizeof(struct bt_mesh_dfu_target)); + if (target_dst->blob.pull) { + target_dst->blob.pull = bt_mesh_calloc(sizeof(struct bt_mesh_blob_target_pull)); + if (!target_dst->blob.pull) { + dfu_targets_free(); + return NULL; + } + memcpy(target_dst->blob.pull, target_src->blob.pull, sizeof(struct bt_mesh_blob_target_pull)); + } else { + target_dst->blob.pull = NULL; + } + target_dst->blob.n.next = NULL; + sys_slist_append(&dst->targets, &target_dst->blob.n); + } + + return dst; +} + static struct bt_mesh_dfu_target *target_get(struct bt_mesh_dfu_cli *cli, uint16_t addr) { @@ -277,6 +354,8 @@ static void dfu_failed(struct bt_mesh_dfu_cli *cli, if (cli->cb && cli->cb->ended) { cli->cb->ended(cli, reason); } + + dfu_targets_free(); } static int req_setup(struct bt_mesh_dfu_cli *cli, enum req type, @@ -839,6 +918,7 @@ static void confirmed(struct bt_mesh_blob_cli *b) if (cli->cb && cli->cb->confirmed) { cli->cb->confirmed(cli); } + dfu_targets_free(); } else { dfu_failed(cli, BLE_MESH_DFU_ERR_INTERNAL); } @@ -1202,6 +1282,12 @@ static void dfu_cli_reset(struct bt_mesh_model *mod) { struct bt_mesh_dfu_cli *cli = mod->user_data; + if (cli->xfer.state == STATE_IDLE) { + return; + } + + dfu_targets_free(); + bt_mesh_dfu_req_list_free(); cli->req = NULL; cli->xfer.state = STATE_IDLE; diff --git a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h index 306af5fbadf..6688ff9142c 100644 --- a/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h +++ b/components/bt/esp_ble_mesh/v1.1/include/mesh_v1.1/dfu/dfu_cli.h @@ -261,6 +261,9 @@ struct bt_mesh_dfu_cli_xfer { const struct bt_mesh_dfu_cli_xfer_blob_params *blob_params; }; +void dfu_targets_free(void); +struct bt_mesh_blob_cli_inputs *dfu_targets_alloc(struct bt_mesh_blob_cli_inputs *src); + /** @brief Start distributing a DFU. * * Starts distribution of the firmware in the given slot to the list of DFU