summaryrefslogtreecommitdiff
path: root/sound/soc
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2021-10-29 21:53:39 +0100
committerMark Brown <broonie@kernel.org>2021-10-29 21:53:39 +0100
commit956ac4f1f53c58f87f38fd79d4c87e9146245c09 (patch)
tree0b24ac9c8d95e8306c89b3242808eb9c34431b35 /sound/soc
parent173632358fde7a567f28e07c4549b959ee857986 (diff)
parent6c504663ba2ee2abeaf5622e27082819326c1bd4 (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/soc')
-rw-r--r--sound/soc/soc-core.c3
-rw-r--r--sound/soc/soc-topology.c34
-rw-r--r--sound/soc/soc-utils.c13
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)