mirror of
https://github.com/torvalds/linux.git
synced 2024-11-14 08:02:07 +00:00
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:
commit
4036d05c38
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user