Merge series "ASoC: topology: fix use-after-free when removing components" from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>:

This patchset fixes a memory allocation issue and removes a 100%
reproducible use-after-free report thrown by KASAN in automated module
removal tests across multiple platforms.

All the credit goes to Bard Liao for root-causing the issue. DAIs may
be registered at the same time as a component, or when the topology is
loaded. This two-step registration causes the memory for
topology-based DAIs to allocated last, and conversely to be released
first by devres, before the component is released and the DAIs removed
from the component DAI list with snd_soc_unregister_dais().

When we remove a component, by the time we walk through its dai list
to unregister all dais, the dais allocated by the topology have been
freed already by devres and the list is corrupted with pointers that
are no longer valid.

The suggestion is to add an explicit devm_ based registration for
topology-based dais, so that each dai is cleanly removed from the
component dai list in the release operation before devres releases the
allocated memory.

Pierre-Louis Bossart (2):
  ASoC: soc-devres: add devm_snd_soc_register_dai()
  ASoC: soc-topology: use devm_snd_soc_register_dai()

 include/sound/soc.h      |  4 ++++
 sound/soc/soc-devres.c   | 37 +++++++++++++++++++++++++++++++++++++
 sound/soc/soc-topology.c |  3 +--
 3 files changed, 42 insertions(+), 2 deletions(-)

--
2.20.1
This commit is contained in:
Mark Brown 2020-06-15 15:18:35 +01:00
commit 4036d05c38
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 42 additions and 2 deletions

View File

@ -1363,6 +1363,10 @@ void snd_soc_remove_pcm_runtime(struct snd_soc_card *card,
struct snd_soc_dai *snd_soc_register_dai(struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
bool legacy_dai_naming);
struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev,
struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
bool legacy_dai_naming);
void snd_soc_unregister_dai(struct snd_soc_dai *dai);
struct snd_soc_dai *snd_soc_find_dai(

View File

@ -9,6 +9,43 @@
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
static void devm_dai_release(struct device *dev, void *res)
{
snd_soc_unregister_dai(*(struct snd_soc_dai **)res);
}
/**
* devm_snd_soc_register_dai - resource-managed dai registration
* @dev: Device used to manage component
* @component: The component the DAIs are registered for
* @dai_drv: DAI driver to use for the DAI
* @legacy_dai_naming: if %true, use legacy single-name format;
* if %false, use multiple-name format;
*/
struct snd_soc_dai *devm_snd_soc_register_dai(struct device *dev,
struct snd_soc_component *component,
struct snd_soc_dai_driver *dai_drv,
bool legacy_dai_naming)
{
struct snd_soc_dai **ptr;
struct snd_soc_dai *dai;
ptr = devres_alloc(devm_dai_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return NULL;
dai = snd_soc_register_dai(component, dai_drv, legacy_dai_naming);
if (dai) {
*ptr = dai;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return dai;
}
EXPORT_SYMBOL_GPL(devm_snd_soc_register_dai);
static void devm_component_release(struct device *dev, void *res)
{
snd_soc_unregister_component(*(struct device **)res);

View File

@ -1851,7 +1851,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
list_add(&dai_drv->dobj.list, &tplg->comp->dobj_list);
/* register the DAI to the component */
dai = snd_soc_register_dai(tplg->comp, dai_drv, false);
dai = devm_snd_soc_register_dai(tplg->comp->dev, tplg->comp, dai_drv, false);
if (!dai)
return -ENOMEM;
@ -1859,7 +1859,6 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
ret = snd_soc_dapm_new_dai_widgets(dapm, dai);
if (ret != 0) {
dev_err(dai->dev, "Failed to create DAI widgets %d\n", ret);
snd_soc_unregister_dai(dai);
return ret;
}