ASoC: wm_asdp: Validate sanity of algorithm count
[deliverable/linux.git] / sound / soc / codecs / wm_adsp.c
index 990403b162feeb35de717578b0ef27529d223abb..017d5101e7897e3ffddd5f918204c1030cf9c5eb 100644 (file)
@@ -156,6 +156,26 @@ static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
        return NULL;
 }
 
+static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region,
+                                         unsigned int offset)
+{
+       switch (region->type) {
+       case WMFW_ADSP1_PM:
+               return region->base + (offset * 3);
+       case WMFW_ADSP1_DM:
+               return region->base + (offset * 2);
+       case WMFW_ADSP2_XM:
+               return region->base + (offset * 2);
+       case WMFW_ADSP2_YM:
+               return region->base + (offset * 2);
+       case WMFW_ADSP1_ZM:
+               return region->base + (offset * 2);
+       default:
+               WARN_ON(NULL != "Unknown memory region type");
+               return offset;
+       }
+}
+
 static int wm_adsp_load(struct wm_adsp *dsp)
 {
        const struct firmware *firmware;
@@ -282,27 +302,27 @@ static int wm_adsp_load(struct wm_adsp *dsp)
                case WMFW_ADSP1_PM:
                        BUG_ON(!mem);
                        region_name = "PM";
-                       reg = mem->base + (offset * 3);
+                       reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP1_DM:
                        BUG_ON(!mem);
                        region_name = "DM";
-                       reg = mem->base + (offset * 2);
+                       reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP2_XM:
                        BUG_ON(!mem);
                        region_name = "XM";
-                       reg = mem->base + (offset * 2);
+                       reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP2_YM:
                        BUG_ON(!mem);
                        region_name = "YM";
-                       reg = mem->base + (offset * 2);
+                       reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                case WMFW_ADSP1_ZM:
                        BUG_ON(!mem);
                        region_name = "ZM";
-                       reg = mem->base + (offset * 2);
+                       reg = wm_adsp_region_to_reg(mem, offset);
                        break;
                default:
                        adsp_warn(dsp,
@@ -357,10 +377,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
        struct wmfw_adsp2_id_hdr adsp2_id;
        struct wmfw_adsp1_alg_hdr *adsp1_alg;
        struct wmfw_adsp2_alg_hdr *adsp2_alg;
-       void *alg;
+       void *alg, *buf;
        const struct wm_adsp_region *mem;
        unsigned int pos, term;
-       size_t algs;
+       size_t algs, buf_size;
        __be32 val;
        int i, ret;
 
@@ -391,6 +411,9 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        return ret;
                }
 
+               buf = &adsp1_id;
+               buf_size = sizeof(adsp1_id);
+
                algs = be32_to_cpu(adsp1_id.algs);
                adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
                          be32_to_cpu(adsp1_id.fw.id),
@@ -412,6 +435,9 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                        return ret;
                }
 
+               buf = &adsp2_id;
+               buf_size = sizeof(adsp2_id);
+
                algs = be32_to_cpu(adsp2_id.algs);
                adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
                          be32_to_cpu(adsp2_id.fw.id),
@@ -434,6 +460,13 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                return -EINVAL;
        }
 
+       if (algs > 1024) {
+               adsp_err(dsp, "Algorithm count %zx excessive\n", algs);
+               print_hex_dump_bytes(dev_name(dsp->dev), DUMP_PREFIX_OFFSET,
+                                    buf, buf_size);
+               return -EINVAL;
+       }
+
        /* Read the terminator first to validate the length */
        ret = regmap_raw_read(regmap, mem->base + term, &val, sizeof(val));
        if (ret != 0) {
This page took 0.030634 seconds and 5 git commands to generate.