diff options
author | Richard Fitzgerald <rf@opensource.wolfsonmicro.com> | 2016-12-20 05:29:12 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-12-20 06:38:49 -0500 |
commit | 1cab2a84f470e15ecc8e5143bfe9398c6e888032 (patch) | |
tree | 2ce157df842149394a8fef82b70d17f336e48947 | |
parent | fb4587da5b1da8415a716193522c395280b4049b (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.c | 25 |
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); | ||
1751 | out: | 1763 | out: |
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); |