ALSA: compress: Fix task creation error unwind

snd_compr_task_new() allocates the driver task before validating the
returned DMA buffers and reserving file descriptors. When either of
those later steps fails, the core frees its task wrapper and DMA-buffer
references without calling the driver's task_free() callback. Any
driver resources allocated by task_create() are therefore leaked.

The dual-fd allocation path also jumps to cleanup without storing the
negative get_unused_fd_flags() result in retval. Since retval still
contains the successful task_create() return value, TASK_CREATE can
incorrectly report success although the task was discarded.

Preserve the fd allocation errors and call task_free() when failure
occurs after a successful task_create() callback.

Fixes: 04177158cf ("ALSA: compress_offload: introduce accel operation mode")
Fixes: 3d3f43fab4 ("ALSA: compress_offload: improve file descriptors installation for dma-buf")
Cc: stable@vger.kernel.org
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260615-alsa-compress-task-unwind-v1-1-39e8ad3ddb27@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Cássio Gabriel 2026-06-15 10:37:26 -03:00 committed by Takashi Iwai
parent c5e90e8844
commit 4a60127deb

View File

@ -1083,15 +1083,18 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
file descriptors are allocated before fd_install() */
if (!task->input || !task->input->file || !task->output || !task->output->file) {
retval = -EINVAL;
goto cleanup;
goto free_driver_task;
}
fd_i = get_unused_fd_flags(O_WRONLY|O_CLOEXEC);
if (fd_i < 0)
goto cleanup;
if (fd_i < 0) {
retval = fd_i;
goto free_driver_task;
}
fd_o = get_unused_fd_flags(O_RDONLY|O_CLOEXEC);
if (fd_o < 0) {
retval = fd_o;
put_unused_fd(fd_i);
goto cleanup;
goto free_driver_task;
}
/* keep dmabuf reference until freed with task free ioctl */
get_dma_buf(task->input);
@ -1103,6 +1106,8 @@ static int snd_compr_task_new(struct snd_compr_stream *stream, struct snd_compr_
list_add_tail(&task->list, &stream->runtime->tasks);
stream->runtime->total_tasks++;
return 0;
free_driver_task:
stream->ops->task_free(stream, task);
cleanup:
snd_compr_task_free(task);
return retval;