From bc791cdf6747b00bfd679a069bc9b4e1ff204989 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 23 Apr 2026 11:21:20 +0800 Subject: [PATCH 1/3] fix(openthread): escape CLI arguments and enforce command buffer bounds --- .../openthread/src/esp_openthread_cli.c | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/components/openthread/src/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c index f87e39f017b..27c6b3cefc3 100644 --- a/components/openthread/src/esp_openthread_cli.c +++ b/components/openthread/src/esp_openthread_cli.c @@ -27,6 +27,29 @@ static TaskHandle_t s_cli_task; +static bool append_escaped_ot_arg(char *buffer, size_t buffer_size, const char *arg) +{ + size_t len = strlen(buffer); + size_t rem_size = (len < buffer_size) ? (buffer_size - len) : 0; + + ESP_RETURN_ON_FALSE(rem_size > 0, false, OT_PLAT_LOG_TAG, "CLI command buffer is full"); + + while (*arg) { + if ((*arg == ' ') || (*arg == '\t') || (*arg == '\r') || (*arg == '\n') || (*arg == '\\')) { + ESP_RETURN_ON_FALSE(rem_size > 1, false, OT_PLAT_LOG_TAG, "CLI command is too long"); + buffer[len++] = '\\'; + rem_size--; + } + + ESP_RETURN_ON_FALSE(rem_size > 1, false, OT_PLAT_LOG_TAG, "CLI command is too long"); + buffer[len++] = *arg++; + rem_size--; + } + + buffer[len] = '\0'; + return true; +} + static int cli_output_callback(void *context, const char *format, va_list args) { char prompt_check[3]; @@ -67,10 +90,14 @@ static int ot_cli_console_callback(int argc, char **argv) { ESP_RETURN_ON_FALSE(argv[1] != NULL && strlen(argv[1]) > 0, ESP_FAIL, OT_PLAT_LOG_TAG, "Invalid OpenThread command"); char cli_cmd[OT_CLI_MAX_LINE_LENGTH] = {0}; - strncpy(cli_cmd, argv[1], sizeof(cli_cmd) - strlen(cli_cmd) - 1); + ESP_RETURN_ON_FALSE(append_escaped_ot_arg(cli_cmd, sizeof(cli_cmd), argv[1]), ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to compose OpenThread command"); for (int i = 2; i < argc; i++) { + ESP_RETURN_ON_FALSE(strlen(cli_cmd) < sizeof(cli_cmd) - 1, ESP_FAIL, OT_PLAT_LOG_TAG, + "CLI command is too long"); strncat(cli_cmd, " ", sizeof(cli_cmd) - strlen(cli_cmd) - 1); - strncat(cli_cmd, argv[i], sizeof(cli_cmd) - strlen(cli_cmd) - 1); + ESP_RETURN_ON_FALSE(append_escaped_ot_arg(cli_cmd, sizeof(cli_cmd), argv[i]), ESP_FAIL, OT_PLAT_LOG_TAG, + "Failed to compose OpenThread command"); } s_cli_task = xTaskGetCurrentTaskHandle(); if (esp_openthread_cli_input(cli_cmd) == ESP_OK) { From ca9a23a6eedd1b2cf3f43782afb98fdc45f90480 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Mon, 27 Apr 2026 18:59:28 +0800 Subject: [PATCH 2/3] feat(openthread): align spinel radio caps with RCP CSMA backoff and TX retry support --- components/openthread/src/esp_openthread_cli.c | 12 +++++++----- .../src/port/esp_openthread_radio_spinel.cpp | 4 +++- .../openthread/src/spinel/esp_radio_spinel.cpp | 4 +++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/components/openthread/src/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c index 27c6b3cefc3..50f90d53c38 100644 --- a/components/openthread/src/esp_openthread_cli.c +++ b/components/openthread/src/esp_openthread_cli.c @@ -35,15 +35,17 @@ static bool append_escaped_ot_arg(char *buffer, size_t buffer_size, const char * ESP_RETURN_ON_FALSE(rem_size > 0, false, OT_PLAT_LOG_TAG, "CLI command buffer is full"); while (*arg) { - if ((*arg == ' ') || (*arg == '\t') || (*arg == '\r') || (*arg == '\n') || (*arg == '\\')) { - ESP_RETURN_ON_FALSE(rem_size > 1, false, OT_PLAT_LOG_TAG, "CLI command is too long"); + bool need_escape = (*arg == ' ') || (*arg == '\t') || (*arg == '\r') || (*arg == '\n') || (*arg == '\\'); + size_t need = need_escape ? 2 : 1; + + ESP_RETURN_ON_FALSE(rem_size >= need, false, OT_PLAT_LOG_TAG, "CLI command is too long"); + + if (need_escape) { buffer[len++] = '\\'; - rem_size--; } - ESP_RETURN_ON_FALSE(rem_size > 1, false, OT_PLAT_LOG_TAG, "CLI command is too long"); buffer[len++] = *arg++; - rem_size--; + rem_size -= need; } buffer[len] = '\0'; diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index b7892da9afa..5978d154210 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -53,7 +53,9 @@ static otRadioCaps s_radio_caps = (OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_RECEIVE_TIMING | OT_RADIO_CAPS_TRANSMIT_TIMING | OT_RADIO_CAPS_ACK_TIMEOUT | - OT_RADIO_CAPS_SLEEP_TO_TX); + OT_RADIO_CAPS_SLEEP_TO_TX | + OT_RADIO_CAPS_CSMA_BACKOFF | + OT_RADIO_CAPS_TRANSMIT_RETRIES); static const char *radiospinel_workflow = "radio_spinel"; static const esp_openthread_radio_config_t *s_esp_openthread_radio_config = NULL; diff --git a/components/openthread/src/spinel/esp_radio_spinel.cpp b/components/openthread/src/spinel/esp_radio_spinel.cpp index 3c35b0cbd8b..06ed3bc6e21 100644 --- a/components/openthread/src/spinel/esp_radio_spinel.cpp +++ b/components/openthread/src/spinel/esp_radio_spinel.cpp @@ -40,7 +40,9 @@ static otRadioCaps s_radio_caps = (OT_RADIO_CAPS_ENERGY_SCAN | OT_RADIO_CAPS_RECEIVE_TIMING | OT_RADIO_CAPS_TRANSMIT_TIMING | OT_RADIO_CAPS_ACK_TIMEOUT | - OT_RADIO_CAPS_SLEEP_TO_TX); + OT_RADIO_CAPS_SLEEP_TO_TX | + OT_RADIO_CAPS_CSMA_BACKOFF | + OT_RADIO_CAPS_TRANSMIT_RETRIES); static esp_radio_spinel_compatibility_error_callback s_radio_spinel_compatibility_error_callback = NULL; static esp_radio_spinel_coprocessor_reset_failure_callback s_radio_spinel_coprocessor_reset_failure_callback = NULL; From 0fefc43f991ccb71f16223b3050a35f02502f6ba Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 30 Apr 2026 10:54:43 +0800 Subject: [PATCH 3/3] fix(openthread): always reserve null-terminator space when appending escaped args --- components/openthread/src/esp_openthread_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openthread/src/esp_openthread_cli.c b/components/openthread/src/esp_openthread_cli.c index 50f90d53c38..59f504c3806 100644 --- a/components/openthread/src/esp_openthread_cli.c +++ b/components/openthread/src/esp_openthread_cli.c @@ -30,7 +30,7 @@ static TaskHandle_t s_cli_task; static bool append_escaped_ot_arg(char *buffer, size_t buffer_size, const char *arg) { size_t len = strlen(buffer); - size_t rem_size = (len < buffer_size) ? (buffer_size - len) : 0; + size_t rem_size = (len < buffer_size) ? (buffer_size - len - 1) : 0; ESP_RETURN_ON_FALSE(rem_size > 0, false, OT_PLAT_LOG_TAG, "CLI command buffer is full");