aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-topology.c')
-rw-r--r--sound/soc/soc-topology.c52
1 files changed, 39 insertions, 13 deletions
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index f6e5ac3e0314..557e22c5254c 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -78,7 +78,7 @@ struct soc_tplg {
};
static int soc_tplg_process_headers(struct soc_tplg *tplg);
-static void soc_tplg_complete(struct soc_tplg *tplg);
+static int soc_tplg_complete(struct soc_tplg *tplg);
/* check we dont overflow the data for this control chunk */
static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
@@ -312,10 +312,12 @@ static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
}
/* tell the component driver that all firmware has been loaded in this request */
-static void soc_tplg_complete(struct soc_tplg *tplg)
+static int soc_tplg_complete(struct soc_tplg *tplg)
{
if (tplg->ops && tplg->ops->complete)
- tplg->ops->complete(tplg->comp);
+ return tplg->ops->complete(tplg->comp);
+
+ return 0;
}
/* add a dynamic kcontrol */
@@ -349,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 */
@@ -1473,10 +1475,6 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
goto widget;
}
- control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
- dev_dbg(tplg->dev, "ASoC: template %s has %d controls of type %x\n",
- w->name, w->num_kcontrols, control_hdr->type);
-
template.num_kcontrols = le32_to_cpu(w->num_kcontrols);
kc = devm_kcalloc(tplg->dev, le32_to_cpu(w->num_kcontrols), sizeof(*kc), GFP_KERNEL);
if (!kc)
@@ -1487,7 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
if (!kcontrol_type)
goto err;
- for (i = 0; i < w->num_kcontrols; i++) {
+ for (i = 0; i < le32_to_cpu(w->num_kcontrols); i++) {
control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
switch (le32_to_cpu(control_hdr->ops.info)) {
case SND_SOC_TPLG_CTL_VOLSW:
@@ -1536,6 +1534,8 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg,
}
template.kcontrol_news = kc;
+ dev_dbg(tplg->dev, "ASoC: template %s with %d/%d/%d (mixer/enum/bytes) control\n",
+ w->name, mixer_count, enum_count, bytes_count);
widget:
ret = soc_tplg_widget_load(tplg, &template, w);
@@ -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,
@@ -2627,7 +2653,7 @@ static int soc_tplg_load(struct soc_tplg *tplg)
ret = soc_tplg_process_headers(tplg);
if (ret == 0)
- soc_tplg_complete(tplg);
+ return soc_tplg_complete(tplg);
return ret;
}
@@ -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;