diff options
Diffstat (limited to 'sound/soc/soc-topology.c')
-rw-r--r-- | sound/soc/soc-topology.c | 52 |
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; |