From 464199f75a56173bc5f22bd4c6bb5ae044c4fdd3 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 30 Jun 2026 16:52:13 +0800 Subject: [PATCH 1/3] fix(adc): add missing input validation for channel and ret_handle - adc_cali_curve_fitting: validate config->chan in check_valid() to prevent OOB access into s_adc_cali_chan_compens compensation table - adc_filter: make s_adc_filter_free idempotent on !UNIT_BINDED SoCs to prevent double-free on repeated adc_del_continuous_iir_filter - adc_cali_line_fitting(esp32): fix config && config typo to config && ret_handle, preventing NULL-pointer dereference --- components/esp_adc/adc_cali_curve_fitting.c | 1 + components/esp_adc/adc_filter.c | 8 ++++++-- components/esp_adc/esp32/adc_cali_line_fitting.c | 5 ++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/components/esp_adc/adc_cali_curve_fitting.c b/components/esp_adc/adc_cali_curve_fitting.c index 919614a5fca..366a5a5a7b4 100644 --- a/components/esp_adc/adc_cali_curve_fitting.c +++ b/components/esp_adc/adc_cali_curve_fitting.c @@ -219,6 +219,7 @@ static esp_err_t check_valid(const adc_cali_curve_fitting_config_t *config) { ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit"); ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation"); + ESP_RETURN_ON_FALSE(config->chan < SOC_ADC_CHANNEL_NUM(config->unit_id), ESP_ERR_INVALID_ARG, TAG, "invalid ADC channel"); bool available_oneshot_bitwidth = (config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH); bool available_dma_bitwidth = (config->bitwidth >= SOC_ADC_DIGI_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_DIGI_MAX_BITWIDTH); diff --git a/components/esp_adc/adc_filter.c b/components/esp_adc/adc_filter.c index da8ead99ea5..2f6c2a6ac8c 100644 --- a/components/esp_adc/adc_filter.c +++ b/components/esp_adc/adc_filter.c @@ -78,11 +78,15 @@ static esp_err_t s_adc_filter_claim(adc_continuous_handle_t handle, adc_iir_filt static esp_err_t s_adc_filter_free(adc_iir_filter_t *filter_ctx) { assert(filter_ctx); + esp_err_t ret = ESP_ERR_NOT_FOUND; portENTER_CRITICAL(&s_filter_spinlock); - filter_ctx->continuous_ctx->iir_filter[filter_ctx->filter_id] = NULL; + if (filter_ctx->continuous_ctx->iir_filter[filter_ctx->filter_id] != NULL) { + filter_ctx->continuous_ctx->iir_filter[filter_ctx->filter_id] = NULL; + ret = ESP_OK; + } portEXIT_CRITICAL(&s_filter_spinlock); - return ESP_OK; + return ret; } #endif diff --git a/components/esp_adc/esp32/adc_cali_line_fitting.c b/components/esp_adc/esp32/adc_cali_line_fitting.c index 60710818584..57175d56106 100644 --- a/components/esp_adc/esp32/adc_cali_line_fitting.c +++ b/components/esp_adc/esp32/adc_cali_line_fitting.c @@ -154,7 +154,7 @@ typedef struct { esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config_t *config, adc_cali_handle_t *ret_handle) { esp_err_t ret = ESP_OK; - ESP_RETURN_ON_FALSE(config && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); + ESP_RETURN_ON_FALSE(config && ret_handle, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer"); ESP_RETURN_ON_FALSE(config->unit_id < SOC_ADC_PERIPH_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC unit"); ESP_RETURN_ON_FALSE(config->atten < SOC_ADC_ATTEN_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid ADC attenuation"); ESP_RETURN_ON_FALSE(((config->bitwidth >= SOC_ADC_RTC_MIN_BITWIDTH && config->bitwidth <= SOC_ADC_RTC_MAX_BITWIDTH) || config->bitwidth == ADC_BITWIDTH_DEFAULT), ESP_ERR_INVALID_ARG, TAG, "invalid bitwidth"); @@ -204,6 +204,9 @@ esp_err_t adc_cali_create_scheme_line_fitting(const adc_cali_line_fitting_config return ESP_OK; err: + if (chars) { + free(chars); + } if (scheme) { free(scheme); } From 0b2cf7f2eaaaca9f7e24dbc798dbd1eeb1cbe2fa Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 30 Jun 2026 16:52:21 +0800 Subject: [PATCH 2/3] fix(i2c): release platform mutex on intr/pm_lock delete failure ESP_RETURN_ON_ERROR inside the s_i2c_platform.mutex critical section returns without releasing the mutex, permanently blocking all I2C bus operations. Replace with ESP_GOTO_ON_ERROR that jumps to a cleanup label releasing the mutex before return. --- components/driver/i2c/i2c_common.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/components/driver/i2c/i2c_common.c b/components/driver/i2c/i2c_common.c index 651e4eeea92..332a63984c2 100644 --- a/components/driver/i2c/i2c_common.c +++ b/components/driver/i2c/i2c_common.c @@ -119,21 +119,28 @@ esp_err_t i2c_acquire_bus_handle(i2c_port_num_t port_num, i2c_bus_handle_t *i2c_ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus) { + esp_err_t ret = ESP_OK; int port_num = i2c_bus->port_num; i2c_clock_source_t clk_src = i2c_bus->clk_src; bool do_deinitialize = false; _lock_acquire(&s_i2c_platform.mutex); if (s_i2c_platform.buses[port_num]) { - s_i2c_platform.count[port_num]--; - if (s_i2c_platform.count[port_num] == 0) { + if (s_i2c_platform.count[port_num] > 1) { + s_i2c_platform.count[port_num]--; + } else { do_deinitialize = true; - s_i2c_platform.buses[port_num] = NULL; if (i2c_bus->intr_handle) { - ESP_RETURN_ON_ERROR(esp_intr_free(i2c_bus->intr_handle), TAG, "delete interrupt service failed"); + ESP_GOTO_ON_ERROR(esp_intr_free(i2c_bus->intr_handle), err, TAG, "delete interrupt service failed"); + i2c_bus->intr_handle = NULL; } +#if CONFIG_PM_ENABLE if (i2c_bus->pm_lock) { - ESP_RETURN_ON_ERROR(esp_pm_lock_delete(i2c_bus->pm_lock), TAG, "delete pm_lock failed"); + esp_pm_lock_delete(i2c_bus->pm_lock); + i2c_bus->pm_lock = NULL; } +#endif + s_i2c_platform.count[port_num] = 0; + s_i2c_platform.buses[port_num] = NULL; // Disable I2C module I2C_RCC_ATOMIC() { i2c_ll_enable_bus_clock(port_num, false); @@ -156,9 +163,11 @@ esp_err_t i2c_release_bus_handle(i2c_bus_handle_t i2c_bus) if (do_deinitialize) { ESP_LOGD(TAG, "delete bus %d", port_num); } - - ESP_RETURN_ON_FALSE(s_i2c_platform.count[port_num] == 0, ESP_ERR_INVALID_STATE, TAG, "Bus not freed entirely"); return ESP_OK; + +err: + _lock_release(&s_i2c_platform.mutex); + return ret; } esp_err_t i2c_select_periph_clock(i2c_bus_handle_t handle, i2c_clock_source_t clk_src) From 9d97e439c86a9aa27984e5a5ecf86a1227eb2e88 Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 30 Jun 2026 17:24:54 +0800 Subject: [PATCH 3/3] fix(sdspi): reject oversized pre-read data before block receive Guard start_command_read_blocks against cards that place TOKEN_BLOCK_START so early that extra_data_size exceeds the bytes expected on the current iteration. Without this check, the unsigned subtraction for will_receive underflows and propagates into memset, SPI transaction length, and memcpy counts against the fixed 516-byte block buffer. --- components/driver/spi/sdspi/sdspi_host.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/components/driver/spi/sdspi/sdspi_host.c b/components/driver/spi/sdspi/sdspi_host.c index 9fb87753a29..9bed2adaff4 100644 --- a/components/driver/spi/sdspi/sdspi_host.c +++ b/components/driver/spi/sdspi/sdspi_host.c @@ -760,7 +760,12 @@ static esp_err_t start_command_read_blocks(slot_info_t *slot, sdspi_hw_cmd_t *cm } // Arrange RX buffer - size_t will_receive = MIN(rx_length, SDSPI_MAX_DATA_LEN) - extra_data_size; + size_t expected_data_size = MIN(rx_length, SDSPI_MAX_DATA_LEN); + if (extra_data_size > expected_data_size) { + ESP_LOGD(TAG, "%s: invalid extra data size %u (expected <= %u)", __func__, (unsigned)extra_data_size, (unsigned)expected_data_size); + return ESP_ERR_INVALID_RESPONSE; + } + size_t will_receive = expected_data_size - extra_data_size; uint8_t* rx_data; ret = get_block_buf(slot, &rx_data); if (ret != ESP_OK) {