Commit 2b13847
committed
pipeline: reject double-connect of already-attached buffer
pipeline_connect() had no guard against being called twice for the same
buffer-component pair. Calling list_item_prepend() on a node that is
already in a doubly-linked list corrupts the list by creating a
self-loop where node->next points back to itself instead of to the list
head.
The corruption was discovered through IPC3 fuzzing in persistent mode.
Without per-testcase topology teardown, components and buffers created
by testcase N survive into testcase N+1. When N+1 sends a
TPLG_COMP_CONNECT for IDs that N already connected, ipc_comp_connect()
finds the surviving objects and calls pipeline_connect() a second time.
The same sequence can also be triggered within a single testcase by two
CONNECT messages for the same pair.
The self-loop causes ipc_comp_free() to hang indefinitely. The function
walks bsource_list / bsink_list with comp_dev_for_each_producer_safe()
whose termination condition checks node->next == &comp->bsource_list.
With the self-loop that check is always false. The walk runs inside
irq_local_disable(), so the native_sim timer cannot preempt the thread
and nsi_exec_for() never returns, making libFuzzer's max_total_time
limit unreachable.
A second failure mode arises when ipc_buffer_free() calls
pipeline_disconnect() on the corrupted buffer. list_item_del() updates
comp->bsource_list.next to node->next, which due to the self-loop is the
node itself — leaving the component's list head pointing into the freed
buffer memory. When that memory is reused by a later allocation and
overwritten, the next walk of bsource_list dereferences an invalid
pointer, crashing with a null dereference or a corrupt-pointer access.
Move the list-consistency check down into buffer_attach() itself, where
it belongs alongside the list_item_prepend() call it protects. The
function is changed to return int: it inspects the buffer's list node
for the given direction via buffer_comp_list() and returns -EALREADY when
list_is_empty() reports the node is already linked (node->next != node),
otherwise prepends and returns 0. pipeline_connect() propagates that
error and emits the component-context log message; the existing single
caller is the only one to update.
Verified with -s address on the full IPC3 corpus (~95K runs, 41 s):
zero crashes, zero hangs, ~2300 exec/s. The unfixed build stalled
indefinitely on the same run.
Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>1 parent 4241c75 commit 2b13847
3 files changed
Lines changed: 21 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
635 | 635 | | |
636 | 636 | | |
637 | 637 | | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
638 | 643 | | |
639 | | - | |
| 644 | + | |
640 | 645 | | |
641 | 646 | | |
642 | 647 | | |
| 648 | + | |
| 649 | + | |
643 | 650 | | |
| 651 | + | |
644 | 652 | | |
645 | 653 | | |
646 | 654 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
198 | 198 | | |
199 | 199 | | |
200 | 200 | | |
| 201 | + | |
201 | 202 | | |
202 | 203 | | |
203 | 204 | | |
| |||
208 | 209 | | |
209 | 210 | | |
210 | 211 | | |
211 | | - | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
212 | 219 | | |
213 | 220 | | |
214 | 221 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
289 | 289 | | |
290 | 290 | | |
291 | 291 | | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
292 | 295 | | |
293 | | - | |
| 296 | + | |
294 | 297 | | |
295 | 298 | | |
296 | 299 | | |
| |||
0 commit comments