Skip to content

Commit 66f2d19

Browse files
committed
ALSA: pcm: Fix memory leak at closing a stream without hw_free
ALSA PCM core recently introduced a new managed PCM buffer allocation mode that does allocate / free automatically at hw_params and hw_free. However, it overlooked the code path directly calling hw_free PCM ops at releasing the PCM substream, and it may result in a memory leak as spotted by syzkaller when no buffer preallocation is used (e.g. vmalloc buffer). This patch papers over it with a slight refactoring. The hw_free ops call and relevant tasks are unified in a new helper function, and call it from both places. Fixes: 0dba808 ("ALSA: pcm: Introduce managed buffer allocation mode") Reported-by: [email protected] Cc: <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent 46b770f commit 66f2d19

File tree

1 file changed

+15
-9
lines changed

1 file changed

+15
-9
lines changed

sound/core/pcm_native.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -786,10 +786,22 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
786786
return err;
787787
}
788788

789+
static int do_hw_free(struct snd_pcm_substream *substream)
790+
{
791+
int result = 0;
792+
793+
snd_pcm_sync_stop(substream);
794+
if (substream->ops->hw_free)
795+
result = substream->ops->hw_free(substream);
796+
if (substream->managed_buffer_alloc)
797+
snd_pcm_lib_free_pages(substream);
798+
return result;
799+
}
800+
789801
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
790802
{
791803
struct snd_pcm_runtime *runtime;
792-
int result = 0;
804+
int result;
793805

794806
if (PCM_RUNTIME_CHECK(substream))
795807
return -ENXIO;
@@ -806,11 +818,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
806818
snd_pcm_stream_unlock_irq(substream);
807819
if (atomic_read(&substream->mmap_count))
808820
return -EBADFD;
809-
snd_pcm_sync_stop(substream);
810-
if (substream->ops->hw_free)
811-
result = substream->ops->hw_free(substream);
812-
if (substream->managed_buffer_alloc)
813-
snd_pcm_lib_free_pages(substream);
821+
result = do_hw_free(substream);
814822
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
815823
pm_qos_remove_request(&substream->latency_pm_qos_req);
816824
return result;
@@ -2529,9 +2537,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
25292537

25302538
snd_pcm_drop(substream);
25312539
if (substream->hw_opened) {
2532-
if (substream->ops->hw_free &&
2533-
substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
2534-
substream->ops->hw_free(substream);
2540+
do_hw_free(substream);
25352541
substream->ops->close(substream);
25362542
substream->hw_opened = 0;
25372543
}

0 commit comments

Comments
 (0)