aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Fitzgerald <rf@opensource.wolfsonmicro.com>2016-12-20 05:29:12 -0500
committerMark Brown <broonie@kernel.org>2016-12-20 06:38:49 -0500
commit1cab2a84f470e15ecc8e5143bfe9398c6e888032 (patch)
tree2ce157df842149394a8fef82b70d17f336e48947
parentfb4587da5b1da8415a716193522c395280b4049b (diff)
ASoC: wm_adsp: Don't overrun firmware file buffer when reading region data
Protect against corrupt firmware files by ensuring that the length we get for the data in a region actually lies within the available firmware file data buffer. Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/wm_adsp.c25
1 files changed, 24 insertions, 1 deletions
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 593b7d1aed46..d72ccef9e238 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -1551,7 +1551,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1551 const struct wmfw_region *region; 1551 const struct wmfw_region *region;
1552 const struct wm_adsp_region *mem; 1552 const struct wm_adsp_region *mem;
1553 const char *region_name; 1553 const char *region_name;
1554 char *file, *text; 1554 char *file, *text = NULL;
1555 struct wm_adsp_buf *buf; 1555 struct wm_adsp_buf *buf;
1556 unsigned int reg; 1556 unsigned int reg;
1557 int regions = 0; 1557 int regions = 0;
@@ -1700,10 +1700,21 @@ static int wm_adsp_load(struct wm_adsp *dsp)
1700 regions, le32_to_cpu(region->len), offset, 1700 regions, le32_to_cpu(region->len), offset,
1701 region_name); 1701 region_name);
1702 1702
1703 if ((pos + le32_to_cpu(region->len) + sizeof(*region)) >
1704 firmware->size) {
1705 adsp_err(dsp,
1706 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
1707 file, regions, region_name,
1708 le32_to_cpu(region->len), firmware->size);
1709 ret = -EINVAL;
1710 goto out_fw;
1711 }
1712
1703 if (text) { 1713 if (text) {
1704 memcpy(text, region->data, le32_to_cpu(region->len)); 1714 memcpy(text, region->data, le32_to_cpu(region->len));
1705 adsp_info(dsp, "%s: %s\n", file, text); 1715 adsp_info(dsp, "%s: %s\n", file, text);
1706 kfree(text); 1716 kfree(text);
1717 text = NULL;
1707 } 1718 }
1708 1719
1709 if (reg) { 1720 if (reg) {
@@ -1748,6 +1759,7 @@ out_fw:
1748 regmap_async_complete(regmap); 1759 regmap_async_complete(regmap);
1749 wm_adsp_buf_free(&buf_list); 1760 wm_adsp_buf_free(&buf_list);
1750 release_firmware(firmware); 1761 release_firmware(firmware);
1762 kfree(text);
1751out: 1763out:
1752 kfree(file); 1764 kfree(file);
1753 1765
@@ -2233,6 +2245,17 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
2233 } 2245 }
2234 2246
2235 if (reg) { 2247 if (reg) {
2248 if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) >
2249 firmware->size) {
2250 adsp_err(dsp,
2251 "%s.%d: %s region len %d bytes exceeds file length %zu\n",
2252 file, blocks, region_name,
2253 le32_to_cpu(blk->len),
2254 firmware->size);
2255 ret = -EINVAL;
2256 goto out_fw;
2257 }
2258
2236 buf = wm_adsp_buf_alloc(blk->data, 2259 buf = wm_adsp_buf_alloc(blk->data,
2237 le32_to_cpu(blk->len), 2260 le32_to_cpu(blk->len),
2238 &buf_list); 2261 &buf_list);