Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer,
int dir)
{
struct list_item *comp_list;
struct list_item *buf_list;
PPL_LOCK_DECLARE;

if (dir == PPL_CONN_DIR_COMP_TO_BUFFER)
Expand All @@ -207,6 +208,29 @@ int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer,

PPL_LOCK();

/*
* Guard against double-connecting the same buffer. Calling
* list_item_prepend() on a node that is already in a list creates a
* self-loop (node->next == node) that permanently corrupts the list.
* Consequences:
* - ipc_comp_free() enters an unbounded loop inside irq_local_disable,
* stalling the simulation indefinitely.
* - pipeline_disconnect() / list_item_del() fails to unlink the buffer
* from the component, leaving a dangling pointer that causes
* use-after-free when the buffer is later freed.
* This can be triggered by a second IPC CONNECT message for the same
* buffer-component pair (within one testcase, or via state carry-over
* between fuzzer testcases when IPC topology is not torn down).
*/
buf_list = dir == PPL_DIR_DOWNSTREAM ?
&buffer->source_list : &buffer->sink_list;
if (!list_is_empty(buf_list)) {
comp_err(comp, "buffer %d already connected dir %d",
buf_get_id(buffer), dir);
PPL_UNLOCK();
return -EINVAL;
}

comp_list = comp_buffer_list(comp, dir);
buffer_attach(buffer, comp_list, dir);
buffer_set_comp(buffer, comp, dir);
Expand Down
Loading