Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d3e2563b authored by Richard Fitzgerald's avatar Richard Fitzgerald Committed by Greg Kroah-Hartman
Browse files

ASoC: wm_adsp: Don't overrun firmware file buffer when reading region data




[ 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: default avatarRichard Fitzgerald <rf@opensource.wolfsonmicro.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a387098f
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -532,7 +532,7 @@ static int wm_adsp_load(struct wm_adsp *dsp)
	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 *dsp)
			 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_adsp *dsp)
		}

		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);