diff mbox series

[2/2] ASoC: topology: don't access beyond topology data

Message ID 20191007084133.7674-3-guennadi.liakhovetski@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series ASoC: topology: fix access beyond data | expand

Commit Message

Guennadi Liakhovetski Oct. 7, 2019, 8:41 a.m. UTC
When loading kcontrol elements make sure to first check the size of
available data before accessing it.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
---
 sound/soc/soc-topology.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index d1d3c6f..f933ad4 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -1115,11 +1115,11 @@  static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
 	struct snd_soc_tplg_hdr *hdr)
 {
 	struct snd_soc_tplg_ctl_hdr *control_hdr;
+	ssize_t remainder = le32_to_cpu(hdr->payload_size);
 	int i;
 
 	if (tplg->pass != SOC_TPLG_PASS_MIXER) {
-		tplg->pos += le32_to_cpu(hdr->size) +
-			le32_to_cpu(hdr->payload_size);
+		tplg->pos += le32_to_cpu(hdr->size) + remainder;
 		return 0;
 	}
 
@@ -1130,6 +1130,11 @@  static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
 
 		control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos;
 
+		if (remainder < sizeof(*control_hdr)) {
+			dev_err(tplg->dev, "ASoC: invalid payload size\n");
+			return -EINVAL;
+		}
+
 		if (le32_to_cpu(control_hdr->size) != sizeof(*control_hdr)) {
 			dev_err(tplg->dev, "ASoC: invalid control size\n");
 			return -EINVAL;
@@ -1143,25 +1148,24 @@  static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg,
 		case SND_SOC_TPLG_CTL_RANGE:
 		case SND_SOC_TPLG_DAPM_CTL_VOLSW:
 		case SND_SOC_TPLG_DAPM_CTL_PIN:
-			soc_tplg_dmixer_create(tplg, 1,
-					       le32_to_cpu(hdr->payload_size));
+			soc_tplg_dmixer_create(tplg, 1, remainder);
 			break;
 		case SND_SOC_TPLG_CTL_ENUM:
 		case SND_SOC_TPLG_CTL_ENUM_VALUE:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
 		case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
-			soc_tplg_denum_create(tplg, 1,
-					      le32_to_cpu(hdr->payload_size));
+			soc_tplg_denum_create(tplg, 1, remainder);
 			break;
 		case SND_SOC_TPLG_CTL_BYTES:
-			soc_tplg_dbytes_create(tplg, 1,
-					       le32_to_cpu(hdr->payload_size));
+			soc_tplg_dbytes_create(tplg, 1, remainder);
 			break;
 		default:
 			soc_bind_err(tplg, control_hdr, i);
 			return -EINVAL;
 		}
+
+		remainder -= tplg->pos - (u8 *)control_hdr;
 	}
 
 	return 0;