Commit efbc17b
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 2b8fc70 commit efbc17b
3 files changed
Lines changed: 21 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
604 | 604 | | |
605 | 605 | | |
606 | 606 | | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
607 | 612 | | |
608 | | - | |
| 613 | + | |
609 | 614 | | |
610 | 615 | | |
611 | 616 | | |
| 617 | + | |
| 618 | + | |
612 | 619 | | |
| 620 | + | |
613 | 621 | | |
614 | 622 | | |
615 | 623 | | |
| |||
| 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