diff options
author | Mark Brown <broonie@kernel.org> | 2021-10-29 21:53:39 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2021-10-29 21:53:39 +0100 |
commit | 956ac4f1f53c58f87f38fd79d4c87e9146245c09 (patch) | |
tree | 0b24ac9c8d95e8306c89b3242808eb9c34431b35 /sound | |
parent | 173632358fde7a567f28e07c4549b959ee857986 (diff) | |
parent | 6c504663ba2ee2abeaf5622e27082819326c1bd4 (diff) |
Merge series "ASoC: Sanity checks and soc-topology updates" from Cezary Rojewski <cezary.rojewski@intel.com>:
Couple of soc-topology related changes and a use-after-free fix. Said fix
and two sanity checks for soc-topology lead the way. While the
use-after-free is quite obvious, the sanity checks are here to cover for
cases where user malformed the topology file -or- access to filesystem
somehow got interrupted during copy operation. We shouldn't be reading
outside the file boundary.
Afterward a change to soc_tplg_add_kcontrol(): device being passed to
soc_tplg_add_dcontrol() from comp->dev to tplg->dev which corrects
dev_xxx() invoked later on.
Also, device used for topology memory allocations from component->dev to
component->card->dev so memory gets freed each time card device (usually
platform device) is removed rather than the component device what may
happen less frequently.
Dummy component gets smarter and no longer overrides hw_params if
there are other components accociated with related struct
snd_soc_pcm_runtime instance.
Amadeusz Sławiński (5):
ASoC: core: Remove invalid snd_soc_component_set_jack call
ASoC: topology: Check for dapm widget completeness
ASoC: topology: Use correct device for prints
ASoC: topology: Change topology device to card device
ASoC: Stop dummy from overriding hwparams
Cezary Rojewski (1):
ASoC: topology: Add header payload_size verification
sound/soc/soc-core.c | 3 ---
sound/soc/soc-topology.c | 34 ++++++++++++++++++++++++++++++----
sound/soc/soc-utils.c | 13 +++++++++++++
3 files changed, 43 insertions(+), 7 deletions(-)
--
2.25.1
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/soc-core.c | 3 | ||||
-rw-r--r-- | sound/soc/soc-topology.c | 34 | ||||
-rw-r--r-- | sound/soc/soc-utils.c | 13 |
3 files changed, 43 insertions, 7 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 94f1548b8a32..dcf6be4c4aaa 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1342,9 +1342,6 @@ static void soc_remove_component(struct snd_soc_component *component, if (probed) snd_soc_component_remove(component); - /* For framework level robustness */ - snd_soc_component_set_jack(component, NULL, NULL); - list_del_init(&component->card_list); snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 7a4559ddf903..557e22c5254c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -351,7 +351,7 @@ static int soc_tplg_add_kcontrol(struct soc_tplg *tplg, struct snd_soc_component *comp = tplg->comp; return soc_tplg_add_dcontrol(comp->card->snd_card, - comp->dev, k, comp->name_prefix, comp, kcontrol); + tplg->dev, k, comp->name_prefix, comp, kcontrol); } /* remove a mixer kcontrol */ @@ -1591,11 +1591,28 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_dapm_widget *widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; int ret; + /* + * check if widget itself fits within topology file + * use sizeof instead of widget->size, as we can't be sure + * it is set properly yet (file may end before it is present) + */ + if (soc_tplg_get_offset(tplg) + sizeof(*widget) >= tplg->fw->size) { + dev_err(tplg->dev, "ASoC: invalid widget data size\n"); + return -EINVAL; + } + + /* check if widget has proper size */ if (le32_to_cpu(widget->size) != sizeof(*widget)) { dev_err(tplg->dev, "ASoC: invalid widget size\n"); return -EINVAL; } + /* check if widget private data fits within topology file */ + if (soc_tplg_get_offset(tplg) + le32_to_cpu(widget->priv.size) >= tplg->fw->size) { + dev_err(tplg->dev, "ASoC: invalid widget private data size\n"); + return -EINVAL; + } + ret = soc_tplg_dapm_widget_create(tplg, widget); if (ret < 0) { dev_err(tplg->dev, "ASoC: failed to load widget %s\n", @@ -2438,6 +2455,7 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, _manifest = manifest; } else { abi_match = false; + ret = manifest_new_ver(tplg, manifest, &_manifest); if (ret < 0) return ret; @@ -2468,6 +2486,14 @@ static int soc_valid_header(struct soc_tplg *tplg, return -EINVAL; } + if (soc_tplg_get_hdr_offset(tplg) + hdr->payload_size >= tplg->fw->size) { + dev_err(tplg->dev, + "ASoC: invalid header of type %d at offset %ld payload_size %d\n", + le32_to_cpu(hdr->type), soc_tplg_get_hdr_offset(tplg), + hdr->payload_size); + return -EINVAL; + } + /* big endian firmware objects not supported atm */ if (le32_to_cpu(hdr->magic) == SOC_TPLG_MAGIC_BIG_ENDIAN) { dev_err(tplg->dev, @@ -2642,17 +2668,17 @@ int snd_soc_tplg_component_load(struct snd_soc_component *comp, /* * check if we have sane parameters: * comp - needs to exist to keep and reference data while parsing - * comp->dev - used for resource management and prints * comp->card - used for setting card related parameters + * comp->card->dev - used for resource management and prints * fw - we need it, as it is the very thing we parse */ - if (!comp || !comp->dev || !comp->card || !fw) + if (!comp || !comp->card || !comp->card->dev || !fw) return -EINVAL; /* setup parsing context */ memset(&tplg, 0, sizeof(tplg)); tplg.fw = fw; - tplg.dev = comp->dev; + tplg.dev = comp->card->dev; tplg.comp = comp; if (ops) { tplg.ops = ops; diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 299b5d6ebfd1..a4efe7e52a8b 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -63,10 +63,23 @@ static const struct snd_pcm_hardware dummy_dma_hardware = { .periods_max = 128, }; + +static const struct snd_soc_component_driver dummy_platform; + static int dummy_dma_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + int i; + + /* + * If there are other components associated with rtd, we shouldn't + * override their hwparams + */ + for_each_rtd_components(rtd, i, component) { + if (component->driver == &dummy_platform) + return 0; + } /* BE's dont need dummy params */ if (!rtd->dai_link->no_pcm) |