From daa66c0646f720fa9e46d7390c8547be6b3b9fb4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 27 Apr 2026 12:29:31 +0200 Subject: [PATCH] overflow: fix some more potential overflows --- spa/plugins/audioconvert/audioconvert.c | 19 ++++++++++++------- spa/plugins/audioconvert/fmt-ops.c | 18 ++++++++++++++---- spa/plugins/filter-graph/filter-graph.c | 16 +++++++++++++--- spa/plugins/videoconvert/videoadapter.c | 9 +++++++-- src/modules/module-loopback.c | 4 ++-- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 17e0f7ff3..440fc6931 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1285,24 +1286,28 @@ static int ensure_tmp(struct impl *this) uint32_t maxsize = this->maxsize, maxports = this->maxports; uint32_t i; float *empty, *scratch, *tmp[2]; + size_t alloc_size; + + if (spa_overflow_add((size_t)maxsize, (size_t)MAX_ALIGN, &alloc_size)) + return -ENOMEM; if (maxsize > this->scratch_size) { spa_log_info(this->log, "resize tmp %d -> %d", this->scratch_size, maxsize); - if ((empty = realloc(this->empty, maxsize + MAX_ALIGN)) != NULL) + if ((empty = realloc(this->empty, alloc_size)) != NULL) this->empty = empty; - if ((scratch = realloc(this->scratch, maxsize + MAX_ALIGN)) != NULL) + if ((scratch = realloc(this->scratch, alloc_size)) != NULL) this->scratch = scratch; if (empty == NULL || scratch == NULL) { free_tmp(this); return -ENOMEM; } - memset(this->empty, 0, maxsize + MAX_ALIGN); + memset(this->empty, 0, alloc_size); for (i = 0; i < this->scratch_ports; i++) { - if ((tmp[0] = realloc(this->tmp[0][i], maxsize + MAX_ALIGN)) != NULL) + if ((tmp[0] = realloc(this->tmp[0][i], alloc_size)) != NULL) this->tmp[0][i] = tmp[0]; - if ((tmp[1] = realloc(this->tmp[1][i], maxsize + MAX_ALIGN)) != NULL) + if ((tmp[1] = realloc(this->tmp[1][i], alloc_size)) != NULL) this->tmp[1][i] = tmp[1]; if (tmp[0] == NULL || tmp[1] == NULL) { free_tmp(this); @@ -1317,9 +1322,9 @@ static int ensure_tmp(struct impl *this) spa_log_info(this->log, "resize ports %d -> %d", this->scratch_ports, maxports); for (i = this->scratch_ports; i < maxports; i++) { - if ((tmp[0] = malloc(maxsize + MAX_ALIGN)) != NULL) + if ((tmp[0] = malloc(alloc_size)) != NULL) this->tmp[0][i] = tmp[0]; - if ((tmp[1] = malloc(maxsize + MAX_ALIGN)) != NULL) + if ((tmp[1] = malloc(alloc_size)) != NULL) this->tmp[1][i] = tmp[1]; if (tmp[0] == NULL || tmp[1] == NULL) { free_tmp(this); diff --git a/spa/plugins/audioconvert/fmt-ops.c b/spa/plugins/audioconvert/fmt-ops.c index 34de40445..734b2d36c 100644 --- a/spa/plugins/audioconvert/fmt-ops.c +++ b/spa/plugins/audioconvert/fmt-ops.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "fmt-ops.h" @@ -551,7 +552,8 @@ int convert_init(struct convert *conv) const struct dither_info *dinfo; const struct noise_info *ninfo; const struct clear_info *cinfo; - uint32_t i, conv_flags, data_size[4]; + uint32_t i, conv_flags; + size_t data_size[4]; /* we generate int32 bits of random values. With this scale * factor, we bring this in the [-1.0, 1.0] range */ @@ -615,10 +617,18 @@ int convert_init(struct convert *conv) data_size[0] = SPA_ROUND_UP(conv->noise_size * sizeof(float), FMT_OPS_MAX_ALIGN); data_size[1] = SPA_ROUND_UP(RANDOM_SIZE * sizeof(uint32_t), FMT_OPS_MAX_ALIGN); data_size[2] = SPA_ROUND_UP(RANDOM_SIZE * sizeof(int32_t), FMT_OPS_MAX_ALIGN); - data_size[3] = SPA_ROUND_UP(conv->n_channels * sizeof(struct shaper), FMT_OPS_MAX_ALIGN); + if (spa_overflow_mul((size_t)conv->n_channels, sizeof(struct shaper), &data_size[3])) + return -ENOMEM; + data_size[3] = SPA_ROUND_UP(data_size[3], FMT_OPS_MAX_ALIGN); - conv->data = calloc(FMT_OPS_MAX_ALIGN + - data_size[0] + data_size[1] + data_size[2] + data_size[3], 1); + size_t total_size = FMT_OPS_MAX_ALIGN; + if (spa_overflow_add(total_size, data_size[0], &total_size) || + spa_overflow_add(total_size, data_size[1], &total_size) || + spa_overflow_add(total_size, data_size[2], &total_size) || + spa_overflow_add(total_size, data_size[3], &total_size)) + return -ENOMEM; + + conv->data = calloc(total_size, 1); if (conv->data == NULL) return -errno; diff --git a/spa/plugins/filter-graph/filter-graph.c b/spa/plugins/filter-graph/filter-graph.c index e88588dfa..c3c5cd629 100644 --- a/spa/plugins/filter-graph/filter-graph.c +++ b/spa/plugins/filter-graph/filter-graph.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -1918,9 +1919,15 @@ static int setup_graph(struct graph *graph) spa_log_info(impl->log, "using %d instances %d %d", n_hndl, n_input, n_output); graph->n_input = 0; - graph->input = calloc(n_input * 16 * n_hndl, sizeof(struct graph_port)); + size_t input_count, output_count; + if (spa_overflow_mul((size_t)n_input, (size_t)16, &input_count) || + spa_overflow_mul(input_count, (size_t)n_hndl, &input_count)) + return -ENOMEM; + graph->input = calloc(input_count, sizeof(struct graph_port)); graph->n_output = 0; - graph->output = calloc(n_output * n_hndl, sizeof(struct graph_port)); + if (spa_overflow_mul((size_t)n_output, (size_t)n_hndl, &output_count)) + return -ENOMEM; + graph->output = calloc(output_count, sizeof(struct graph_port)); /* now collect all input and output ports for all the handles. */ for (i = 0; i < n_hndl; i++) { @@ -2059,7 +2066,10 @@ static int setup_graph(struct graph *graph) } graph->n_hndl = 0; - graph->hndl = calloc(graph->n_nodes * n_hndl, sizeof(struct graph_hndl)); + size_t hndl_count; + if (spa_overflow_mul((size_t)graph->n_nodes, (size_t)n_hndl, &hndl_count)) + return -ENOMEM; + graph->hndl = calloc(hndl_count, sizeof(struct graph_hndl)); /* order all nodes based on dependencies, first reset fields */ sort_reset(graph); while ((node = sort_next_node(graph)) != NULL) { diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c index fe50413aa..088a807bd 100644 --- a/spa/plugins/videoconvert/videoadapter.c +++ b/spa/plugins/videoconvert/videoadapter.c @@ -358,6 +358,7 @@ static void emit_node_info(struct impl *this, bool full) if (this->info.props) n_items = this->info.props->n_items; + n_items = SPA_MIN(n_items, 1024u); items = alloca((n_items + 2) * sizeof(struct spa_dict_item)); for (i = 0; i < n_items; i++) items[i] = this->info.props->items[i]; @@ -518,6 +519,9 @@ static int negotiate_buffers(struct impl *this) align = SPA_MAX(align, this->max_align); + if (blocks > 4096) + return -ENOMEM; + datas = alloca(sizeof(struct spa_data) * blocks); memset(datas, 0, sizeof(struct spa_data) * blocks); aligns = alloca(sizeof(uint32_t) * blocks); @@ -1910,9 +1914,10 @@ static int load_converter(struct impl *this, const struct spa_dict *info, char direction[16]; uint32_t i; - items = alloca((info->n_items + 1) * sizeof(struct spa_dict_item)); + uint32_t n_items = SPA_MIN(info->n_items, 1024u); + items = alloca((n_items + 1) * sizeof(struct spa_dict_item)); cinfo = SPA_DICT(items, 0); - for (i = 0; i < info->n_items; i++) + for (i = 0; i < n_items; i++) items[cinfo.n_items++] = info->items[i]; snprintf(direction, sizeof(direction), "%s", diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index 35c3f812d..d1725751c 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -580,14 +580,14 @@ static void recalculate_buffer(struct impl *impl) size_t alloc_size; if (spa_overflow_add(delay, 1u << 15, &impl->buffer_size) || - spa_overflow_mul(impl->buffer_size, 4u, &impl->buffer_size)) { + spa_overflow_mul(impl->buffer_size, 4u, &impl->buffer_size) || + spa_overflow_mul((size_t)impl->buffer_size, (size_t)impl->channels, &alloc_size)) { pw_log_warn("delay too large, delay disabled"); impl->buffer_size = 0; free(impl->buffer_data); impl->buffer_data = NULL; goto done; } - alloc_size = (size_t)impl->buffer_size * impl->channels; data = realloc(impl->buffer_data, alloc_size); if (data == NULL) { pw_log_warn("can't allocate delay buffer, delay disabled: %m");