From f8eb9d8d967cb3edc80bed17d866824614c7d522 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 11 Jun 2026 13:08:52 +0100 Subject: [PATCH 1/3] igo_nr: reject out-of-range control switch element count The switch get handler looped over a host-supplied element count while writing the reply channel array and reading per-channel state. Reject counts larger than the maximum channel count before the loop. Signed-off-by: Liam Girdwood --- src/audio/igo_nr/igo_nr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index e398af7d964b..89fae92b4438 100644 --- a/src/audio/igo_nr/igo_nr.c +++ b/src/audio/igo_nr/igo_nr.c @@ -566,6 +566,11 @@ static int igo_nr_get_config(struct processing_module *mod, comp_info(dev, "SOF_CTRL_CMD_BINARY"); return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size); case SOF_CTRL_CMD_SWITCH: + if (cdata->num_elems > SOF_IPC_MAX_CHANNELS) { + comp_err(dev, "igo_nr_get_config() error: num_elems %u out of range", + cdata->num_elems); + return -EINVAL; + } for (j = 0; j < cdata->num_elems; j++) { cdata->chanv[j].channel = j; cdata->chanv[j].value = cd->process_enable[j]; From 133784c16e63615a34e410673d8e0529358c90bc Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 11 Jun 2026 13:08:52 +0100 Subject: [PATCH 2/3] igo_nr: validate config blob size before copy A new configuration blob was copied into the component state as a fixed-size structure without checking the blob was large enough, reading past the allocation for a short blob. Request the blob size and reject one smaller than the configuration structure. Signed-off-by: Liam Girdwood --- src/audio/igo_nr/igo_nr.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index 89fae92b4438..35da0d634808 100644 --- a/src/audio/igo_nr/igo_nr.c +++ b/src/audio/igo_nr/igo_nr.c @@ -720,13 +720,26 @@ static void igo_nr_print_config(struct processing_module *mod) static void igo_nr_set_igo_params(struct processing_module *mod) { struct comp_data *cd = module_get_private_data(mod); - struct sof_igo_nr_config *p_config = comp_get_data_blob(cd->model_handler, NULL, NULL); + size_t config_size = 0; + struct sof_igo_nr_config *p_config = comp_get_data_blob(cd->model_handler, + &config_size, NULL); struct comp_dev *dev = mod->dev; comp_info(dev, "entry"); - igo_nr_check_config_validity(dev, cd); if (p_config) { + if (config_size < sizeof(cd->config)) { + comp_err(dev, "New config too small: %zu < %zu", + config_size, sizeof(cd->config)); + return; + } + /* validate the incoming blob and only apply it if it passes; + * igo_nr_check_config_validity() re-reads the new blob + */ + if (igo_nr_check_config_validity(dev, cd) < 0) { + comp_err(dev, "New config failed validation, not applied"); + return; + } comp_info(dev, "New config detected."); cd->config = *p_config; igo_nr_print_config(mod); From 7f5aebc6f7fbebb92acddb2f29a4af366ef557ff Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 11 Jun 2026 14:30:37 +0100 Subject: [PATCH 3/3] igo_nr: compute circular buffer ends in samples not bytes The processing buffers' end pointers were computed by adding a byte count to sample-typed pointers, placing the end past the real buffer and letting the wrap check pass too late. Convert the byte sizes to element counts when computing the ends. Signed-off-by: Liam Girdwood --- src/audio/igo_nr/igo_nr.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/audio/igo_nr/igo_nr.c b/src/audio/igo_nr/igo_nr.c index 35da0d634808..44a879b5dd1c 100644 --- a/src/audio/igo_nr/igo_nr.c +++ b/src/audio/igo_nr/igo_nr.c @@ -72,7 +72,7 @@ static int igo_nr_capture_s16(struct comp_data *cd, int16_t *x, *y1, *y2; int16_t *x_start, *y_start, *x_end, *y_end; int16_t sample; - size_t x_size, y_size; + int x_size, y_size; size_t request_size = frames * source_get_frame_bytes(source); int sink_samples_without_wrap; int samples_without_wrap; @@ -93,12 +93,15 @@ static int igo_nr_capture_s16(struct comp_data *cd, #endif - ret = source_get_data(source, request_size, (void const **)&x, - (void const **)&x_start, &x_size); + /* use the sample-count source/sink accessors so the returned sizes are + * already in samples and need no byte-to-element conversion + */ + ret = source_get_data_s16(source, request_size, (int16_t const **)&x, + (int16_t const **)&x_start, &x_size); if (ret) return ret; - ret = sink_get_buffer(sink, request_size, (void **)&y1, (void **)&y_start, &y_size); + ret = sink_get_buffer_s16(sink, request_size, &y1, &y_start, &y_size); if (ret) { source_release_data(source, 0); return ret; @@ -174,7 +177,7 @@ static int igo_nr_capture_s24(struct comp_data *cd, { int32_t *x, *y1, *y2; int32_t *x_start, *y_start, *x_end, *y_end; - size_t x_size, y_size; + int x_size, y_size; size_t request_size = frames * source_get_frame_bytes(source); int sink_samples_without_wrap; int samples_without_wrap; @@ -195,12 +198,15 @@ static int igo_nr_capture_s24(struct comp_data *cd, #endif - ret = source_get_data(source, request_size, (void const **)&x, - (void const **)&x_start, &x_size); + /* use the sample-count source/sink accessors so the returned sizes are + * already in samples and need no byte-to-element conversion + */ + ret = source_get_data_s32(source, request_size, (int32_t const **)&x, + (int32_t const **)&x_start, &x_size); if (ret) return ret; - ret = sink_get_buffer(sink, request_size, (void **)&y1, (void **)&y_start, &y_size); + ret = sink_get_buffer_s32(sink, request_size, &y1, &y_start, &y_size); if (ret) { source_release_data(source, 0); return ret; @@ -275,7 +281,7 @@ static int igo_nr_capture_s32(struct comp_data *cd, { int32_t *x, *y1, *y2; int32_t *x_start, *y_start, *x_end, *y_end; - size_t x_size, y_size; + int x_size, y_size; size_t request_size = frames * source_get_frame_bytes(source); int sink_samples_without_wrap; int samples_without_wrap; @@ -296,12 +302,15 @@ static int igo_nr_capture_s32(struct comp_data *cd, #endif - ret = source_get_data(source, request_size, (void const **)&x, - (void const **)&x_start, &x_size); + /* use the sample-count source/sink accessors so the returned sizes are + * already in samples and need no byte-to-element conversion + */ + ret = source_get_data_s32(source, request_size, (int32_t const **)&x, + (int32_t const **)&x_start, &x_size); if (ret) return ret; - ret = sink_get_buffer(sink, request_size, (void **)&y1, (void **)&y_start, &y_size); + ret = sink_get_buffer_s32(sink, request_size, &y1, &y_start, &y_size); if (ret) { source_release_data(source, 0); return ret;