* [alsa-devel] [PATCH] ALSA: pcm: Fix memory leak at closing a stream without hw_free
@ 2020-01-29 19:59 Takashi Iwai
2020-02-12 23:26 ` Pierre-Louis Bossart
0 siblings, 1 reply; 4+ messages in thread
From: Takashi Iwai @ 2020-01-29 19:59 UTC (permalink / raw)
To: alsa-devel
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: 0dba808eae26 ("ALSA: pcm: Introduce managed buffer allocation mode")
Reported-by: syzbot+30edd0f34bfcdc548ac4@syzkaller.appspotmail.com
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/core/pcm_native.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index bb23f5066654..4ac42ee1238c 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -786,10 +786,22 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
return err;
}
+static int do_hw_free(struct snd_pcm_substream *substream)
+{
+ int result = 0;
+
+ snd_pcm_sync_stop(substream);
+ if (substream->ops->hw_free)
+ result = substream->ops->hw_free(substream);
+ if (substream->managed_buffer_alloc)
+ snd_pcm_lib_free_pages(substream);
+ return result;
+}
+
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
- int result = 0;
+ int result;
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
@@ -806,11 +818,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
snd_pcm_stream_unlock_irq(substream);
if (atomic_read(&substream->mmap_count))
return -EBADFD;
- snd_pcm_sync_stop(substream);
- if (substream->ops->hw_free)
- result = substream->ops->hw_free(substream);
- if (substream->managed_buffer_alloc)
- snd_pcm_lib_free_pages(substream);
+ result = do_hw_free(substream);
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
pm_qos_remove_request(&substream->latency_pm_qos_req);
return result;
@@ -2529,9 +2537,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
snd_pcm_drop(substream);
if (substream->hw_opened) {
- if (substream->ops->hw_free &&
- substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
- substream->ops->hw_free(substream);
+ do_hw_free(substream);
substream->ops->close(substream);
substream->hw_opened = 0;
}
--
2.16.4
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [alsa-devel] [PATCH] ALSA: pcm: Fix memory leak at closing a stream without hw_free
2020-01-29 19:59 [alsa-devel] [PATCH] ALSA: pcm: Fix memory leak at closing a stream without hw_free Takashi Iwai
@ 2020-02-12 23:26 ` Pierre-Louis Bossart
2020-02-13 6:17 ` Takashi Iwai
0 siblings, 1 reply; 4+ messages in thread
From: Pierre-Louis Bossart @ 2020-02-12 23:26 UTC (permalink / raw)
To: Takashi Iwai, alsa-devel, Mark Brown, Kai Vehmanen, Bard liao,
Ranjani Sridharan
On 1/29/20 1:59 PM, Takashi Iwai wrote:
> 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: 0dba808eae26 ("ALSA: pcm: Introduce managed buffer allocation mode")
> Reported-by: syzbot+30edd0f34bfcdc548ac4@syzkaller.appspotmail.com
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Takashi, this patch introduces a regression for our SoundWire work -
credits to Bard Liao for reporting this the first.
We see the hw_free() being called twice and as a result the SoundWire
stream state becomes inconsistent, with some memory becoming corrupted:
[ 107.864109] sof-audio-pci 0000:00:1f.3: pcm: free stream 0 dir 0
[ 107.864324] sof-audio-pci 0000:00:1f.3: ipc tx: 0x80010000:
GLB_DAI_MSG: CONFIG
[ 107.864507] sof-audio-pci 0000:00:1f.3: ipc tx succeeded: 0x80010000:
GLB_DAI_MSG: CONFIG
[ 107.864615] sof-audio-pci 0000:00:1f.3: pcm: free stream 0 dir 0
[ 107.864627] sdw_deprepare_stream: \xc0Pjf\xe0\xa3\xff\xff:
inconsistent state state 6
[ 107.864640] int-sdw int-sdw.0: sdw_deprepare_stream: failed -22
we detected this while merging your latest code as part of our weekly
rebase, then realized the error was already present in v5.6-rc1 and
continued to narrow the scope to sound-fix-5.6-rc1 and this specific patch.
I can't claim to fully understand the code in this patch, but I am not
sure why hw_free() ends up being unconditionally called at [1] below
> ---
> sound/core/pcm_native.c | 24 +++++++++++++++---------
> 1 file changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index bb23f5066654..4ac42ee1238c 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -786,10 +786,22 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
> return err;
> }
>
> +static int do_hw_free(struct snd_pcm_substream *substream)
> +{
> + int result = 0;
> +
> + snd_pcm_sync_stop(substream);
> + if (substream->ops->hw_free)
> + result = substream->ops->hw_free(substream);
> + if (substream->managed_buffer_alloc)
> + snd_pcm_lib_free_pages(substream);
> + return result;
> +}
> +
> static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
> {
> struct snd_pcm_runtime *runtime;
> - int result = 0;
> + int result;
>
> if (PCM_RUNTIME_CHECK(substream))
> return -ENXIO;
> @@ -806,11 +818,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
> snd_pcm_stream_unlock_irq(substream);
> if (atomic_read(&substream->mmap_count))
> return -EBADFD;
> - snd_pcm_sync_stop(substream);
> - if (substream->ops->hw_free)
> - result = substream->ops->hw_free(substream);
> - if (substream->managed_buffer_alloc)
> - snd_pcm_lib_free_pages(substream);
> + result = do_hw_free(substream);
> snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
> pm_qos_remove_request(&substream->latency_pm_qos_req);
> return result;
> @@ -2529,9 +2537,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
>
> snd_pcm_drop(substream);
> if (substream->hw_opened) {
> - if (substream->ops->hw_free &&
> - substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
> - substream->ops->hw_free(substream);
> + do_hw_free(substream);
[1] don't we need to only do the hw_free() when
substream->runtime->status->state != SNDRV_PCM_STATE_OPEN
e.g. with the following patch?
Or is the expectation that the hw_free() callback be implemented so that
only the first call has an effect?
Thanks
-Pierre
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 336406bcb59e..051a1f234975 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -787,12 +787,12 @@ static int snd_pcm_hw_params_user(struct
snd_pcm_substream *substream,
return err;
}
-static int do_hw_free(struct snd_pcm_substream *substream)
+static int do_hw_free(struct snd_pcm_substream *substream, bool cond_free)
{
int result = 0;
snd_pcm_sync_stop(substream);
- if (substream->ops->hw_free)
+ if (cond_free && substream->ops->hw_free)
result = substream->ops->hw_free(substream);
if (substream->managed_buffer_alloc)
snd_pcm_lib_free_pages(substream);
@@ -819,7 +819,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream
*substream)
snd_pcm_stream_unlock_irq(substream);
if (atomic_read(&substream->mmap_count))
return -EBADFD;
- result = do_hw_free(substream);
+ result = do_hw_free(substream, true);
snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
pm_qos_remove_request(&substream->latency_pm_qos_req);
return result;
@@ -2594,7 +2594,9 @@ void snd_pcm_release_substream(struct
snd_pcm_substream *substream)
snd_pcm_drop(substream);
if (substream->hw_opened) {
- do_hw_free(substream);
+ do_hw_free(substream,
+ substream->runtime->status->state !=
+ SNDRV_PCM_STATE_OPEN);
substream->ops->close(substream);
substream->hw_opened = 0;
}
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [alsa-devel] [PATCH] ALSA: pcm: Fix memory leak at closing a stream without hw_free
2020-02-12 23:26 ` Pierre-Louis Bossart
@ 2020-02-13 6:17 ` Takashi Iwai
2020-02-13 15:24 ` Pierre-Louis Bossart
0 siblings, 1 reply; 4+ messages in thread
From: Takashi Iwai @ 2020-02-13 6:17 UTC (permalink / raw)
To: Pierre-Louis Bossart
Cc: alsa-devel, Mark Brown, Bard liao, Ranjani Sridharan, Kai Vehmanen
On Thu, 13 Feb 2020 00:26:44 +0100,
Pierre-Louis Bossart wrote:
>
>
>
> On 1/29/20 1:59 PM, Takashi Iwai wrote:
> > 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: 0dba808eae26 ("ALSA: pcm: Introduce managed buffer allocation mode")
> > Reported-by: syzbot+30edd0f34bfcdc548ac4@syzkaller.appspotmail.com
> > Cc: <stable@vger.kernel.org>
> > Signed-off-by: Takashi Iwai <tiwai@suse.de>
>
> Takashi, this patch introduces a regression for our SoundWire work -
> credits to Bard Liao for reporting this the first.
>
> We see the hw_free() being called twice and as a result the SoundWire
> stream state becomes inconsistent, with some memory becoming
> corrupted:
>
> [ 107.864109] sof-audio-pci 0000:00:1f.3: pcm: free stream 0 dir 0
> [ 107.864324] sof-audio-pci 0000:00:1f.3: ipc tx: 0x80010000:
> GLB_DAI_MSG: CONFIG
> [ 107.864507] sof-audio-pci 0000:00:1f.3: ipc tx succeeded:
> 0x80010000: GLB_DAI_MSG: CONFIG
> [ 107.864615] sof-audio-pci 0000:00:1f.3: pcm: free stream 0 dir 0
> [ 107.864627] sdw_deprepare_stream: \xc0Pjf\xe0\xa3\xff\xff:
> inconsistent state state 6
> [ 107.864640] int-sdw int-sdw.0: sdw_deprepare_stream: failed -22
>
> we detected this while merging your latest code as part of our weekly
> rebase, then realized the error was already present in v5.6-rc1 and
> continued to narrow the scope to sound-fix-5.6-rc1 and this specific
> patch.
>
> I can't claim to fully understand the code in this patch, but I am not
> sure why hw_free() ends up being unconditionally called at [1] below
>
> > ---
> > sound/core/pcm_native.c | 24 +++++++++++++++---------
> > 1 file changed, 15 insertions(+), 9 deletions(-)
> >
> > diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> > index bb23f5066654..4ac42ee1238c 100644
> > --- a/sound/core/pcm_native.c
> > +++ b/sound/core/pcm_native.c
> > @@ -786,10 +786,22 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
> > return err;
> > }
> > +static int do_hw_free(struct snd_pcm_substream *substream)
> > +{
> > + int result = 0;
> > +
> > + snd_pcm_sync_stop(substream);
> > + if (substream->ops->hw_free)
> > + result = substream->ops->hw_free(substream);
> > + if (substream->managed_buffer_alloc)
> > + snd_pcm_lib_free_pages(substream);
> > + return result;
> > +}
> > +
> > static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
> > {
> > struct snd_pcm_runtime *runtime;
> > - int result = 0;
> > + int result;
> > if (PCM_RUNTIME_CHECK(substream))
> > return -ENXIO;
> > @@ -806,11 +818,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
> > snd_pcm_stream_unlock_irq(substream);
> > if (atomic_read(&substream->mmap_count))
> > return -EBADFD;
> > - snd_pcm_sync_stop(substream);
> > - if (substream->ops->hw_free)
> > - result = substream->ops->hw_free(substream);
> > - if (substream->managed_buffer_alloc)
> > - snd_pcm_lib_free_pages(substream);
> > + result = do_hw_free(substream);
> > snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
> > pm_qos_remove_request(&substream->latency_pm_qos_req);
> > return result;
> > @@ -2529,9 +2537,7 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
> > snd_pcm_drop(substream);
> > if (substream->hw_opened) {
> > - if (substream->ops->hw_free &&
> > - substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
> > - substream->ops->hw_free(substream);
> > + do_hw_free(substream);
>
> [1] don't we need to only do the hw_free() when
>
> substream->runtime->status->state != SNDRV_PCM_STATE_OPEN
>
> e.g. with the following patch?
Yes, my bad, it's just an oversight.
But the condition check should be applied to the whole do_hw_free()
call, so it can be simpler like the patch below.
> Or is the expectation that the hw_free() callback be implemented so
> that only the first call has an effect?
This is another solution, but let's follow to the original code that
had the condition check at the caller side.
thanks,
Takashi
-- 8< --
From: Takashi Iwai <tiwai@suse.de>
Subject: [PATCH] ALSA: pcm: Fix double hw_free calls
The commit 66f2d19f8116 ("ALSA: pcm: Fix memory leak at closing a
stream without hw_free") tried to fix the regression wrt the missing
hw_free call at closing without SNDRV_PCM_IOCTL_HW_FREE ioctl.
However, the code change dropped mistakenly the state check, resulting
in calling hw_free twice when SNDRV_PCM_IOCTL_HW_FRE got called
beforehand. For most drivers, this is almost harmless, but the
drivers like SOF show another regression now.
This patch adds the state condition check before calling do_hw_free()
at releasing the stream for avoiding the double hw_free calls.
Fixes: 66f2d19f8116 ("ALSA: pcm: Fix memory leak at closing a stream without hw_free")
Reported-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reported-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
---
sound/core/pcm_native.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 336406bcb59e..d5443eeb8b63 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -2594,7 +2594,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
snd_pcm_drop(substream);
if (substream->hw_opened) {
- do_hw_free(substream);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ do_hw_free(substream);
substream->ops->close(substream);
substream->hw_opened = 0;
}
--
2.16.4
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [alsa-devel] [PATCH] ALSA: pcm: Fix memory leak at closing a stream without hw_free
2020-02-13 6:17 ` Takashi Iwai
@ 2020-02-13 15:24 ` Pierre-Louis Bossart
0 siblings, 0 replies; 4+ messages in thread
From: Pierre-Louis Bossart @ 2020-02-13 15:24 UTC (permalink / raw)
To: Takashi Iwai
Cc: alsa-devel, Mark Brown, Bard liao, Ranjani Sridharan, Kai Vehmanen
> From: Takashi Iwai <tiwai@suse.de>
> Subject: [PATCH] ALSA: pcm: Fix double hw_free calls
>
> The commit 66f2d19f8116 ("ALSA: pcm: Fix memory leak at closing a
> stream without hw_free") tried to fix the regression wrt the missing
> hw_free call at closing without SNDRV_PCM_IOCTL_HW_FREE ioctl.
> However, the code change dropped mistakenly the state check, resulting
> in calling hw_free twice when SNDRV_PCM_IOCTL_HW_FRE got called
> beforehand. For most drivers, this is almost harmless, but the
> drivers like SOF show another regression now.
>
> This patch adds the state condition check before calling do_hw_free()
> at releasing the stream for avoiding the double hw_free calls.
>
> Fixes: 66f2d19f8116 ("ALSA: pcm: Fix memory leak at closing a stream without hw_free")
> Reported-by: Bard Liao <yung-chuan.liao@linux.intel.com>
> Reported-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Tested-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Thanks Takashi!
> ---
> sound/core/pcm_native.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index 336406bcb59e..d5443eeb8b63 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -2594,7 +2594,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
>
> snd_pcm_drop(substream);
> if (substream->hw_opened) {
> - do_hw_free(substream);
> + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
> + do_hw_free(substream);
> substream->ops->close(substream);
> substream->hw_opened = 0;
> }
>
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-02-13 15:25 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-29 19:59 [alsa-devel] [PATCH] ALSA: pcm: Fix memory leak at closing a stream without hw_free Takashi Iwai
2020-02-12 23:26 ` Pierre-Louis Bossart
2020-02-13 6:17 ` Takashi Iwai
2020-02-13 15:24 ` Pierre-Louis Bossart
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).