Tplg parser security fixes#10896
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds defensive bounds checking and safer string formatting to harden the topology parser and related tooling against malformed/untrusted inputs.
Changes:
- Introduces a topology buffer bounds-check macro and applies it to multiple topology accessors.
- Replaces unsafe
strcat()concatenation with size-boundedsnprintf()in graph pipeline-string construction. - Adds a sanity limit for probe packet data sizes to avoid oversized allocations/copies.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| tools/tplg_parser/include/tplg_parser/topology.h | Adds bounds checking helpers and applies them to topology object getters; extends tplg_create_graph() API with buffer size. |
| tools/tplg_parser/graph.c | Uses snprintf() with remaining capacity to avoid strcat() overflows when building the pipeline string. |
| tools/testbench/topology_ipc3.c | Updates caller to pass pipeline_string capacity to tplg_create_graph(). |
| tools/probes/probes_demux.c | Adds a maximum allowed probe packet data size and rejects oversized packets. |
| #define tplg_skip_hdr_payload(ctx) \ | ||
| ({struct snd_soc_tplg_hdr *ptr; \ | ||
| tplg_check_bounds(ctx, hdr->payload_size); \ | ||
| ptr = (struct snd_soc_tplg_hdr *)(ctx->tplg_base + ctx->tplg_offset); \ | ||
| ctx->tplg_offset += hdr->payload_size; (void *)ptr; }) |
There was a problem hiding this comment.
Nothing to do with this PR. These are not general purpose macros, but just a short hand in writing topology parser. The code is not even used for anything any more. So I am not going to fix all issues found from these sources.
| #define tplg_check_bounds(ctx, advance) \ | ||
| do { \ | ||
| if ((long)(advance) < 0 || \ | ||
| ctx->tplg_offset + (long)(advance) > (long)ctx->tplg_size) { \ | ||
| printf("%s %d topology offset %ld + %ld > size %zu\n", \ | ||
| __func__, __LINE__, ctx->tplg_offset, \ | ||
| (long)(advance), ctx->tplg_size); \ | ||
| assert(0); \ | ||
| } \ | ||
| } while (0) |
There was a problem hiding this comment.
Will put an exit(1) there instead.
| size_t cur_len = strlen(pipeline_string); | ||
| size_t remaining = pipeline_string_size > cur_len ? | ||
| pipeline_string_size - cur_len : 0; | ||
| int written; | ||
|
|
||
| if (route_num == (count - 1)) | ||
| written = snprintf(pipeline_string + cur_len, remaining, | ||
| "%s->%s\n", graph_elem->source, | ||
| graph_elem->sink); | ||
| else | ||
| written = snprintf(pipeline_string + cur_len, remaining, | ||
| "%s->", graph_elem->source); | ||
|
|
||
| if (written < 0 || (size_t)written >= remaining) | ||
| fprintf(stderr, "warning: pipeline string truncated\n"); |
There was a problem hiding this comment.
Put copilot to work, and then let it check its work, and then fix yourself.
| #define APP_NAME "sof-probes" | ||
|
|
||
| #define PACKET_MAX_SIZE 4096 /**< Size limit for probe data packet */ | ||
| #define PACKET_DATA_SIZE_MAX (16 * 1024 * 1024) /**< Sanity limit for packet data size */ |
| ctx->tplg_offset + (long)(advance) > (long)ctx->tplg_size) { \ | ||
| printf("%s %d topology offset %ld + %ld > size %zu\n", \ | ||
| __func__, __LINE__, ctx->tplg_offset, \ | ||
| (long)(advance), ctx->tplg_size); \ |
There was a problem hiding this comment.
ctx should be in parentheses
There was a problem hiding this comment.
It is missing there is several other macros that were there before this commit. I'll adda another commit on top and fix them all in that one.
| ({void *ptr; ptr = ctx->tplg_base + ctx->tplg_offset; \ | ||
| ({void *ptr; \ | ||
| tplg_check_bounds(ctx, sizeof(*(obj)) + (priv_size)); \ | ||
| ptr = ctx->tplg_base + ctx->tplg_offset; \ |
There was a problem hiding this comment.
same in these macros and below too
0e95cfa to
58d22fc
Compare
Add tplg_check_bounds() macro that validates ctx->tplg_offset + advance does not exceed ctx->tplg_size before advancing the offset. Apply this check in all topology object reader macros: tplg_get_hdr, tplg_skip_hdr_payload, tplg_get_object, tplg_get_object_priv, tplg_get_widget, tplg_get_graph, and tplg_get_pcm. Without these checks, a crafted .tplg file with malicious payload_size or priv.size values can drive the offset past the end of the mapped topology data, causing out-of-bounds reads in all subsequent object parsing. Signed-off-by: Jyri Sarha <jyri.sarha@intel.com>
58d22fc to
08892a2
Compare
Add () around all macro argument instances. Signed-off-by: Jyri Sarha <jyri.sarha@linux.intel.com>
Replace unbounded strcat() calls with snprintf() that tracks remaining buffer capacity. Add a pipeline_string_size parameter to tplg_create_graph() so the function knows the buffer limit. Without this fix, a crafted topology file with many or long graph element names can overflow the caller's fixed 256-byte pipeline_string buffer via repeated strcat(), corrupting the host stack. Signed-off-by: Jyri Sarha <jyri.sarha@intel.com>
…erflow Add a sanity check in process_sync() to reject packets with data_size_bytes exceeding 16 MiB before performing the data_size_bytes + sizeof(uint64_t) addition used for realloc sizing. Without this check, a crafted probe dump with data_size_bytes near UINT32_MAX wraps the realloc size to a small value, then the subsequent data copy writes data_size_bytes into the undersized buffer. Signed-off-by: Jyri Sarha <jyri.sarha@intel.com>
08892a2 to
d1ffb2b
Compare
Security fixes for development toos.