Skip to content

Commit c58099b

Browse files
committed
ipc4: helper: reject module creation for non-existent pipeline
comp_new_ipc4() copied the host-supplied ppl_instance_id into ipc_config.pipeline_id without verifying that the referenced pipeline exists. The module_adapter creation path then does: ipc_pipe = ipc_get_comp_by_ppl_id(ipc, COMP_TYPE_PIPELINE, config->pipeline_id, IPC_COMP_IGNORE_REMOTE); if (ipc_pipe) dev->pipeline = ipc_pipe->pipeline; /* skipped when NULL */ so when the pipeline is missing the lookup returns NULL, the assignment is skipped, and the component is created with dev->pipeline left unset. A gateway module such as the copier then dereferences that NULL pointer while wiring the graph, e.g. copier_dai_init() writing pipeline->source_comp / pipeline->sink_comp, giving a NULL-pointer SEGV reachable from a single unprivileged IPC. The case -------- The offending IPC stream carries one meaningful command: a MODULE / INIT_INSTANCE request for a copier-class module (module_id 26, instance_id 36) whose extension.ppl_instance_id names a parent pipeline (id 90) for which no GLB / CREATE_PIPELINE command was ever sent. That pipeline is therefore absent from ipc->comp_list. IPC4 mandates that the host create the pipeline before instantiating any module inside it; here that ordering is violated, so the invariant "an INIT_INSTANCE always targets an existing pipeline" does not hold. The firmware accepted the request anyway, allocated the component, ran module_init() -> copier_init() -> copier_dai_create(), and copier_dai_init() performed a WRITE to the source_comp field (offset 0x54) through the NULL dev->pipeline, faulting on the zero page: ERROR: SEGV on unknown address 0x00000054 (WRITE) copier_dai_init -> copier_dai_create -> copier_init -> module_init -> module_adapter_new_ext -> module_adapter_new -> comp_new_ipc4 -> ipc4_init_module_instance -> ipc4_process_module_message -> ipc_cmd All three copier gateway variants are affected (copier_host_create, copier_dai_create and copier_ipcgtw_create all pass dev->pipeline down), and any future module reading dev->pipeline during init would hit the same latent NULL. Fix --- Reject the request at the common creation entry point: in comp_new_ipc4(), before the component is allocated, look up the parent pipeline and fail with a NULL return (reported to the host as IPC4_MOD_NOT_INITIALIZED) when it does not exist. This fails fast with no partially-initialized component to unwind, and the later module_adapter lookup is then guaranteed to succeed. The lookup uses IPC_COMP_ALL so it stays core-agnostic: a valid parent pipeline may run on a different core than the module being instantiated (e.g. a DP module scheduled on a separate core). Not every module has a parent pipeline, so the check cannot enforce a blanket "a live component always belongs to a live pipeline" invariant: base firmware modules such as the probe are instantiated with the reserved ppl_instance_id value IPC4_INVALID_PIPELINE_ID (0xFF), which is not a pipeline id. Exempt that value from the check so those modules are still accepted; they never dereference dev->pipeline. That exemption means a gateway copier could still be created with no pipeline (0xFF). Unlike the probe, a gateway copier must be wired into the graph and therefore requires a live pipeline, so reject it in copier_init() before the gateway create path dereferences dev->pipeline. Together this keeps "no NULL dev->pipeline dereference is reachable from a single IPC" for every module driver. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
1 parent 22cae7b commit c58099b

3 files changed

Lines changed: 28 additions & 0 deletions

File tree

src/audio/copier/copier.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,16 @@ __cold static int copier_init(struct processing_module *mod)
176176
node_id = copier->gtw_cfg.node_id;
177177
/* copier is linked to gateway */
178178
if (node_id.dw != IPC4_INVALID_NODE_ID) {
179+
/* A gateway copier wires itself into the pipeline graph, so it needs a
180+
* valid parent pipeline (base FW modules using IPC4_INVALID_PIPELINE_ID
181+
* are exempt in comp_new_ipc4()). Reject here to avoid a NULL deref.
182+
*/
183+
if (!dev->pipeline) {
184+
comp_err(dev, "gateway copier requires a valid parent pipeline");
185+
ret = -EINVAL;
186+
goto error;
187+
}
188+
179189
cd->direction = get_gateway_direction(node_id.f.dma_type);
180190

181191
switch (node_id.f.dma_type) {

src/include/ipc4/module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,10 @@ struct ipc4_module_init_data {
151151
152152
\remark hide_methods
153153
*/
154+
155+
/* Reserved ppl_instance_id: module has no parent pipeline (e.g. probe). */
156+
#define IPC4_INVALID_PIPELINE_ID 0xFF
157+
154158
struct ipc4_module_init_instance {
155159

156160
union {

src/ipc/ipc4/helper.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,20 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i
145145
ipc_config.ipc_config_size);
146146
return NULL;
147147
}
148+
149+
/* Reject a module naming a non-existent parent pipeline: otherwise
150+
* dev->pipeline stays NULL and a later init path (e.g. the copier)
151+
* dereferences it. IPC4_INVALID_PIPELINE_ID is exempt - it marks base FW
152+
* modules with no parent pipeline. IPC_COMP_ALL: the pipeline may run on a
153+
* different core than this module.
154+
*/
155+
if (ipc_config.pipeline_id != IPC4_INVALID_PIPELINE_ID &&
156+
!ipc_get_comp_by_ppl_id(ipc_get(), COMP_TYPE_PIPELINE, ipc_config.pipeline_id,
157+
IPC_COMP_ALL)) {
158+
tr_err(&ipc_tr, "comp 0x%x: parent pipeline %u does not exist", comp_id,
159+
(uint32_t)ipc_config.pipeline_id);
160+
return NULL;
161+
}
148162
#ifdef CONFIG_DCACHE_LINE_SIZE
149163
if (!IS_ENABLED(CONFIG_LIBRARY))
150164
sys_cache_data_invd_range((__sparse_force void __sparse_cache *)

0 commit comments

Comments
 (0)