| From foo@baz Tue Nov 28 10:58:31 CET 2017 |
| From: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
| Date: Tue, 20 Dec 2016 10:29:12 +0000 |
| Subject: ASoC: wm_adsp: Don't overrun firmware file buffer when reading region data |
| |
| From: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> |
| |
| |
| [ Upstream commit 1cab2a84f470e15ecc8e5143bfe9398c6e888032 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| sound/soc/codecs/wm_adsp.c | 25 ++++++++++++++++++++++++- |
| 1 file changed, 24 insertions(+), 1 deletion(-) |
| |
| --- a/sound/soc/codecs/wm_adsp.c |
| +++ b/sound/soc/codecs/wm_adsp.c |
| @@ -532,7 +532,7 @@ static int wm_adsp_load(struct wm_adsp * |
| const struct wmfw_region *region; |
| const struct wm_adsp_region *mem; |
| const char *region_name; |
| - char *file, *text; |
| + char *file, *text = NULL; |
| struct wm_adsp_buf *buf; |
| unsigned int reg; |
| int regions = 0; |
| @@ -677,10 +677,21 @@ static int wm_adsp_load(struct wm_adsp * |
| regions, le32_to_cpu(region->len), offset, |
| region_name); |
| |
| + if ((pos + le32_to_cpu(region->len) + sizeof(*region)) > |
| + firmware->size) { |
| + adsp_err(dsp, |
| + "%s.%d: %s region len %d bytes exceeds file length %zu\n", |
| + file, regions, region_name, |
| + le32_to_cpu(region->len), firmware->size); |
| + ret = -EINVAL; |
| + goto out_fw; |
| + } |
| + |
| if (text) { |
| memcpy(text, region->data, le32_to_cpu(region->len)); |
| adsp_info(dsp, "%s: %s\n", file, text); |
| kfree(text); |
| + text = NULL; |
| } |
| |
| if (reg) { |
| @@ -737,6 +748,7 @@ out_fw: |
| regmap_async_complete(regmap); |
| wm_adsp_buf_free(&buf_list); |
| release_firmware(firmware); |
| + kfree(text); |
| out: |
| kfree(file); |
| |
| @@ -1316,6 +1328,17 @@ static int wm_adsp_load_coeff(struct wm_ |
| } |
| |
| if (reg) { |
| + if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) > |
| + firmware->size) { |
| + adsp_err(dsp, |
| + "%s.%d: %s region len %d bytes exceeds file length %zu\n", |
| + file, blocks, region_name, |
| + le32_to_cpu(blk->len), |
| + firmware->size); |
| + ret = -EINVAL; |
| + goto out_fw; |
| + } |
| + |
| buf = wm_adsp_buf_alloc(blk->data, |
| le32_to_cpu(blk->len), |
| &buf_list); |