| @@ -1107,9 +1107,16 @@ struct cs_dsp_coeff_parsed_coeff { · 1106 unmodified lines |
| 1107 | int len; | 1107 | int len; |
| 1108 | }; | 1108 | }; |
| 1109 | | 1109 | |
| 1110 | static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) | 1110 | static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, unsigned int avail, |
| | 1111 | const u8 **str) |
| 1111 | { | 1112 | { |
| 1112 | int length; | 1113 | int length, total_field_len; |
| | 1114 | |
| | 1115 | /* String fields are at least one __le32 */ |
| | 1116 | if (sizeof(__le32) > avail) { |
| | 1117 | *pos = NULL; |
| | 1118 | return 0; |
| | 1119 | } |
| 1113 | | 1120 | |
| 1114 | switch (bytes) { | 1121 | switch (bytes) { |
| 1115 | case 1: | 1122 | case 1: |
| @@ -1122,10 +1129,16 @@ static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) · 6 unmodified lines |
| 1122 | return 0; | 1129 | return 0; |
| 1123 | } | 1130 | } |
| 1124 | | 1131 | |
| | 1132 | total_field_len = ((length + bytes) + 3) & ~0x03; |
| | 1133 | if ((unsigned int)total_field_len > avail) { |
| | 1134 | *pos = NULL; |
| | 1135 | return 0; |
| | 1136 | } |
| | 1137 | |
| 1125 | if (str) | 1138 | if (str) |
| 1126 | *str = *pos + bytes; | 1139 | *str = *pos + bytes; |
| 1127 | | 1140 | |
| 1128 | *pos += ((length + bytes) + 3) & ~0x03; | 1141 | *pos += total_field_len; |
| 1129 | | 1142 | |
| 1130 | return length; | 1143 | return length; |
| 1131 | } | 1144 | } |
| @@ -1150,71 +1163,134 @@ static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos) · 18 unmodified lines |
| 1150 | return val; | 1163 | return val; |
| 1151 | } | 1164 | } |
| 1152 | | 1165 | |
| 1153 | static inline void cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, const u8 **data, | 1166 | static int cs_dsp_coeff_parse_alg(struct cs_dsp *dsp, |
| 1154 | struct cs_dsp_coeff_parsed_alg *blk) | 1167 | const struct wmfw_region *region, |
| | 1168 | struct cs_dsp_coeff_parsed_alg *blk) |
| 1155 | { | 1169 | { |
| 1156 | const struct wmfw_adsp_alg_data *raw; | 1170 | const struct wmfw_adsp_alg_data *raw; |
| | 1171 | unsigned int data_len = le32_to_cpu(region->len); |
| | 1172 | unsigned int pos; |
| | 1173 | const u8 *tmp; |
| | 1174 | |
| | 1175 | raw = (const struct wmfw_adsp_alg_data *)region->data; |
| 1157 | | 1176 | |
| 1158 | switch (dsp->fw_ver) { | 1177 | switch (dsp->fw_ver) { |
| 1159 | case 0: | 1178 | case 0: |
| 1160 | case 1: | 1179 | case 1: |
| 1161 | raw = (const struct wmfw_adsp_alg_data *)*data; | 1180 | if (sizeof(*raw) > data_len) |
| 1162 | *data = raw->data; | 1181 | return -EOVERFLOW; |
| 1163 | | 1182 | |
| 1164 | blk->id = le32_to_cpu(raw->id); | 1183 | blk->id = le32_to_cpu(raw->id); |
| 1165 | blk->name = raw->name; | 1184 | blk->name = raw->name; |
| 1166 | blk->name_len = strlen(raw->name); | 1185 | blk->name_len = strnlen(raw->name, ARRAY_SIZE(raw->name)); |
| 1167 | blk->ncoeff = le32_to_cpu(raw->ncoeff); | 1186 | blk->ncoeff = le32_to_cpu(raw->ncoeff); |
| | 1187 | |
| | 1188 | pos = sizeof(*raw); |
| 1168 | break; | 1189 | break; |
| 1169 | default: | 1190 | default: |
| 1170 | blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), data); | 1191 | if (sizeof(raw->id) > data_len) |
| 1171 | blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), data, | 1192 | return -EOVERFLOW; |
| | 1193 | |
| | 1194 | tmp = region->data; |
| | 1195 | blk->id = cs_dsp_coeff_parse_int(sizeof(raw->id), &tmp); |
| | 1196 | pos = tmp - region->data; |
| | 1197 | |
| | 1198 | tmp = ®ion->data[pos]; |
| | 1199 | blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, |
| 1172 | &blk->name); | 1200 | &blk->name); |
| 1173 | cs_dsp_coeff_parse_string(sizeof(u16), data, NULL); | 1201 | if (!tmp) |
| 1174 | blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), data); | 1202 | return -EOVERFLOW; |
| | 1203 | |
| | 1204 | pos = tmp - region->data; |
| | 1205 | cs_dsp_coeff_parse_string(sizeof(u16), &tmp, data_len - pos, NULL); |
| | 1206 | if (!tmp) |
| | 1207 | return -EOVERFLOW; |
| | 1208 | |
| | 1209 | pos = tmp - region->data; |
| | 1210 | if (sizeof(raw->ncoeff) > (data_len - pos)) |
| | 1211 | return -EOVERFLOW; |
| | 1212 | |
| | 1213 | blk->ncoeff = cs_dsp_coeff_parse_int(sizeof(raw->ncoeff), &tmp); |
| | 1214 | pos += sizeof(raw->ncoeff); |
| 1175 | break; | 1215 | break; |
| 1176 | } | 1216 | } |
| 1177 | | 1217 | |
| | 1218 | if ((int)blk->ncoeff < 0) |
| | 1219 | return -EOVERFLOW; |
| | 1220 | |
| 1178 | cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); | 1221 | cs_dsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); |
| 1179 | cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); | 1222 | cs_dsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); |
| 1180 | cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); | 1223 | cs_dsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); |
| | 1224 | |
| | 1225 | return pos; |
| 1181 | } | 1226 | } |
| 1182 | | 1227 | |
| 1183 | static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, | 1228 | static int cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, |
| 1184 | struct cs_dsp_coeff_parsed_coeff *blk) | 1229 | const struct wmfw_region *region, |
| | 1230 | unsigned int pos, |
| | 1231 | struct cs_dsp_coeff_parsed_coeff *blk) |
| 1185 | { | 1232 | { |
| 1186 | const struct wmfw_adsp_coeff_data *raw; | 1233 | const struct wmfw_adsp_coeff_data *raw; |
| | 1234 | unsigned int data_len = le32_to_cpu(region->len); |
| | 1235 | unsigned int blk_len, blk_end_pos; |
| 1187 | const u8 *tmp; | 1236 | const u8 *tmp; |
| 1188 | int length; | 1237 | |
| | 1238 | raw = (const struct wmfw_adsp_coeff_data *)®ion->data[pos]; |
| | 1239 | if (sizeof(raw->hdr) > (data_len - pos)) |
| | 1240 | return -EOVERFLOW; |
| | 1241 | |
| | 1242 | blk_len = le32_to_cpu(raw->hdr.size); |
| | 1243 | if (blk_len > S32_MAX) |
| | 1244 | return -EOVERFLOW; |
| | 1245 | |
| | 1246 | if (blk_len > (data_len - pos - sizeof(raw->hdr))) |
| | 1247 | return -EOVERFLOW; |
| | 1248 | |
| | 1249 | blk_end_pos = pos + sizeof(raw->hdr) + blk_len; |
| | 1250 | |
| | 1251 | blk->offset = le16_to_cpu(raw->hdr.offset); |
| | 1252 | blk->mem_type = le16_to_cpu(raw->hdr.type); |
| 1189 | | 1253 | |
| 1190 | switch (dsp->fw_ver) { | 1254 | switch (dsp->fw_ver) { |
| 1191 | case 0: | 1255 | case 0: |
| 1192 | case 1: | 1256 | case 1: |
| 1193 | raw = (const struct wmfw_adsp_coeff_data *)*data; | 1257 | if (sizeof(*raw) > (data_len - pos)) |
| 1194 | *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); | 1258 | return -EOVERFLOW; |
| 1195 | | 1259 | |
| 1196 | blk->offset = le16_to_cpu(raw->hdr.offset); | | |
| 1197 | blk->mem_type = le16_to_cpu(raw->hdr.type); | | |
| 1198 | blk->name = raw->name; | 1260 | blk->name = raw->name; |
| 1199 | blk->name_len = strlen(raw->name); | 1261 | blk->name_len = strnlen(raw->name, ARRAY_SIZE(raw->name)); |
| 1200 | blk->ctl_type = le16_to_cpu(raw->ctl_type); | 1262 | blk->ctl_type = le16_to_cpu(raw->ctl_type); |
| 1201 | blk->flags = le16_to_cpu(raw->flags); | 1263 | blk->flags = le16_to_cpu(raw->flags); |
| 1202 | blk->len = le32_to_cpu(raw->len); | 1264 | blk->len = le32_to_cpu(raw->len); |
| 1203 | break; | 1265 | break; |
| 1204 | default: | 1266 | default: |
| 1205 | tmp = *data; | 1267 | pos += sizeof(raw->hdr); |
| 1206 | blk->offset = cs_dsp_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); | 1268 | tmp = ®ion->data[pos]; |
| 1207 | blk->mem_type = cs_dsp_coeff_parse_int(sizeof(raw->hdr.type), &tmp); | 1269 | blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, |
| 1208 | length = cs_dsp_coeff_parse_int(sizeof(raw->hdr.size), &tmp); | | |
| 1209 | blk->name_len = cs_dsp_coeff_parse_string(sizeof(u8), &tmp, | | |
| 1210 | &blk->name); | 1270 | &blk->name); |
| 1211 | cs_dsp_coeff_parse_string(sizeof(u8), &tmp, NULL); | 1271 | if (!tmp) |
| 1212 | cs_dsp_coeff_parse_string(sizeof(u16), &tmp, NULL); | 1272 | return -EOVERFLOW; |
| | 1273 | |
| | 1274 | pos = tmp - region->data; |
| | 1275 | cs_dsp_coeff_parse_string(sizeof(u8), &tmp, data_len - pos, NULL); |
| | 1276 | if (!tmp) |
| | 1277 | return -EOVERFLOW; |
| | 1278 | |
| | 1279 | pos = tmp - region->data; |
| | 1280 | cs_dsp_coeff_parse_string(sizeof(u16), &tmp, data_len - pos, NULL); |
| | 1281 | if (!tmp) |
| | 1282 | return -EOVERFLOW; |
| | 1283 | |
| | 1284 | pos = tmp - region->data; |
| | 1285 | if (sizeof(raw->ctl_type) + sizeof(raw->flags) + sizeof(raw->len) > |
| | 1286 | (data_len - pos)) |
| | 1287 | return -EOVERFLOW; |
| | 1288 | |
| 1213 | blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); | 1289 | blk->ctl_type = cs_dsp_coeff_parse_int(sizeof(raw->ctl_type), &tmp); |
| | 1290 | pos += sizeof(raw->ctl_type); |
| 1214 | blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); | 1291 | blk->flags = cs_dsp_coeff_parse_int(sizeof(raw->flags), &tmp); |
| | 1292 | pos += sizeof(raw->flags); |
| 1215 | blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); | 1293 | blk->len = cs_dsp_coeff_parse_int(sizeof(raw->len), &tmp); |
| 1216 | | | |
| 1217 | *data = *data + sizeof(raw->hdr) + length; | | |
| 1218 | break; | 1294 | break; |
| 1219 | } | 1295 | } |
| 1220 | | 1296 | |
| @@ -1224,6 +1300,8 @@ static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data, · 3 unmodified lines |
| 1224 | cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); | 1300 | cs_dsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); |
| 1225 | cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); | 1301 | cs_dsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); |
| 1226 | cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); | 1302 | cs_dsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); |
| | 1303 | |
| | 1304 | return blk_end_pos; |
| 1227 | } | 1305 | } |
| 1228 | | 1306 | |
| 1229 | static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, | 1307 | static int cs_dsp_check_coeff_flags(struct cs_dsp *dsp, |
| @@ -1247,12 +1325,16 @@ static int cs_dsp_parse_coeff(struct cs_dsp *dsp, · 17 unmodified lines |
| 1247 | struct cs_dsp_alg_region alg_region = {}; | 1325 | struct cs_dsp_alg_region alg_region = {}; |
| 1248 | struct cs_dsp_coeff_parsed_alg alg_blk; | 1326 | struct cs_dsp_coeff_parsed_alg alg_blk; |
| 1249 | struct cs_dsp_coeff_parsed_coeff coeff_blk; | 1327 | struct cs_dsp_coeff_parsed_coeff coeff_blk; |
| 1250 | const u8 *data = region->data; | 1328 | int i, pos, ret; |
| 1251 | int i, ret; | 1329 | |
| | 1330 | pos = cs_dsp_coeff_parse_alg(dsp, region, &alg_blk); |
| | 1331 | if (pos < 0) |
| | 1332 | return pos; |
| 1252 | | 1333 | |
| 1253 | cs_dsp_coeff_parse_alg(dsp, &data, &alg_blk); | | |
| 1254 | for (i = 0; i < alg_blk.ncoeff; i++) { | 1334 | for (i = 0; i < alg_blk.ncoeff; i++) { |
| 1255 | cs_dsp_coeff_parse_coeff(dsp, &data, &coeff_blk); | 1335 | pos = cs_dsp_coeff_parse_coeff(dsp, region, pos, &coeff_blk); |
| | 1336 | if (pos < 0) |
| | 1337 | return pos; |
| 1256 | | 1338 | |
| 1257 | switch (coeff_blk.ctl_type) { | 1339 | switch (coeff_blk.ctl_type) { |
| 1258 | case WMFW_CTL_TYPE_BYTES: | 1340 | case WMFW_CTL_TYPE_BYTES: |
| @@ -1321,6 +1403,10 @@ static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp, · 62 unmodified lines |
| 1321 | const struct wmfw_adsp1_sizes *adsp1_sizes; | 1403 | const struct wmfw_adsp1_sizes *adsp1_sizes; |
| 1322 | | 1404 | |
| 1323 | adsp1_sizes = (void *)&firmware->data[pos]; | 1405 | adsp1_sizes = (void *)&firmware->data[pos]; |
| | 1406 | if (sizeof(*adsp1_sizes) > firmware->size - pos) { |
| | 1407 | cs_dsp_err(dsp, "%s: file truncated\n", file); |
| | 1408 | return 0; |
| | 1409 | } |
| 1324 | | 1410 | |
| 1325 | cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, | 1411 | cs_dsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", file, |
| 1326 | le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), | 1412 | le32_to_cpu(adsp1_sizes->dm), le32_to_cpu(adsp1_sizes->pm), |
| @@ -1337,6 +1423,10 @@ static unsigned int cs_dsp_adsp2_parse_sizes(struct cs_dsp *dsp, · 10 unmodified lines |
| 1337 | const struct wmfw_adsp2_sizes *adsp2_sizes; | 1423 | const struct wmfw_adsp2_sizes *adsp2_sizes; |
| 1338 | | 1424 | |
| 1339 | adsp2_sizes = (void *)&firmware->data[pos]; | 1425 | adsp2_sizes = (void *)&firmware->data[pos]; |
| | 1426 | if (sizeof(*adsp2_sizes) > firmware->size - pos) { |
| | 1427 | cs_dsp_err(dsp, "%s: file truncated\n", file); |
| | 1428 | return 0; |
| | 1429 | } |
| 1340 | | 1430 | |
| 1341 | cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, | 1431 | cs_dsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", file, |
| 1342 | le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), | 1432 | le32_to_cpu(adsp2_sizes->xm), le32_to_cpu(adsp2_sizes->ym), |
| @@ -1376,7 +1466,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, · 33 unmodified lines |
| 1376 | struct regmap *regmap = dsp->regmap; | 1466 | struct regmap *regmap = dsp->regmap; |
| 1377 | unsigned int pos = 0; | 1467 | unsigned int pos = 0; |
| 1378 | const struct wmfw_header *header; | 1468 | const struct wmfw_header *header; |
| 1379 | const struct wmfw_adsp1_sizes *adsp1_sizes; | | |
| 1380 | const struct wmfw_footer *footer; | 1469 | const struct wmfw_footer *footer; |
| 1381 | const struct wmfw_region *region; | 1470 | const struct wmfw_region *region; |
| 1382 | const struct cs_dsp_region *mem; | 1471 | const struct cs_dsp_region *mem; |
| @@ -1392,10 +1481,8 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, · 9 unmodified lines |
| 1392 | | 1481 | |
| 1393 | ret = -EINVAL; | 1482 | ret = -EINVAL; |
| 1394 | | 1483 | |
| 1395 | pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); | 1484 | if (sizeof(*header) >= firmware->size) { |
| 1396 | if (pos >= firmware->size) { | 1485 | ret = -EOVERFLOW; |
| 1397 | cs_dsp_err(dsp, "%s: file too short, %zu bytes\n", | | |
| 1398 | file, firmware->size); | | |
| 1399 | goto out_fw; | 1486 | goto out_fw; |
| 1400 | } | 1487 | } |
| 1401 | | 1488 | |
| @@ -1423,22 +1510,36 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, · 21 unmodified lines |
| 1423 | | 1510 | |
| 1424 | pos = sizeof(*header); | 1511 | pos = sizeof(*header); |
| 1425 | pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); | 1512 | pos = dsp->ops->parse_sizes(dsp, file, pos, firmware); |
| | 1513 | if ((pos == 0) || (sizeof(*footer) > firmware->size - pos)) { |
| | 1514 | ret = -EOVERFLOW; |
| | 1515 | goto out_fw; |
| | 1516 | } |
| 1426 | | 1517 | |
| 1427 | footer = (void *)&firmware->data[pos]; | 1518 | footer = (void *)&firmware->data[pos]; |
| 1428 | pos += sizeof(*footer); | 1519 | pos += sizeof(*footer); |
| 1429 | | 1520 | |
| 1430 | if (le32_to_cpu(header->len) != pos) { | 1521 | if (le32_to_cpu(header->len) != pos) { |
| 1431 | cs_dsp_err(dsp, "%s: unexpected header length %d\n", | 1522 | ret = -EOVERFLOW; |
| 1432 | file, le32_to_cpu(header->len)); | | |
| 1433 | goto out_fw; | 1523 | goto out_fw; |
| 1434 | } | 1524 | } |
| 1435 | | 1525 | |
| 1436 | cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, | 1526 | cs_dsp_dbg(dsp, "%s: timestamp %llu\n", file, |
| 1437 | le64_to_cpu(footer->timestamp)); | 1527 | le64_to_cpu(footer->timestamp)); |
| 1438 | | 1528 | |
| 1439 | while (pos < firmware->size && | 1529 | while (pos < firmware->size) { |
| 1440 | sizeof(*region) < firmware->size - pos) { | 1530 | /* Is there enough data for a complete block header? */ |
| | 1531 | if (sizeof(*region) > firmware->size - pos) { |
| | 1532 | ret = -EOVERFLOW; |
| | 1533 | goto out_fw; |
| | 1534 | } |
| | 1535 | |
| 1441 | region = (void *)&(firmware->data[pos]); | 1536 | region = (void *)&(firmware->data[pos]); |
| | 1537 | |
| | 1538 | if (le32_to_cpu(region->len) > firmware->size - pos - sizeof(*region)) { |
| | 1539 | ret = -EOVERFLOW; |
| | 1540 | goto out_fw; |
| | 1541 | } |
| | 1542 | |
| 1442 | region_name = "Unknown"; | 1543 | region_name = "Unknown"; |
| 1443 | reg = 0; | 1544 | reg = 0; |
| 1444 | text = NULL; | 1545 | text = NULL; |
| @@ -1495,16 +1596,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware, · 50 unmodified lines |
| 1495 | regions, le32_to_cpu(region->len), offset, | 1596 | regions, le32_to_cpu(region->len), offset, |
| 1496 | region_name); | 1597 | region_name); |
| 1497 | | 1598 | |
| 1498 | if (le32_to_cpu(region->len) > | | |
| 1499 | firmware->size - pos - sizeof(*region)) { | | |
| 1500 | cs_dsp_err(dsp, | | |
| 1501 | "%s.%d: %s region len %d bytes exceeds file length %zu\n", | | |
| 1502 | file, regions, region_name, | | |
| 1503 | le32_to_cpu(region->len), firmware->size); | | |
| 1504 | ret = -EINVAL; | | |
| 1505 | goto out_fw; | | |
| 1506 | } | | |
| 1507 | | | |
| 1508 | if (text) { | 1599 | if (text) { |
| 1509 | memcpy(text, region->data, le32_to_cpu(region->len)); | 1600 | memcpy(text, region->data, le32_to_cpu(region->len)); |
| 1510 | cs_dsp_info(dsp, "%s: %s\n", file, text); | 1601 | cs_dsp_info(dsp, "%s: %s\n", file, text); |
| @@ -1555,6 +1646,9 @@ out_fw: · 44 unmodified lines |
| 1555 | cs_dsp_buf_free(&buf_list); | 1646 | cs_dsp_buf_free(&buf_list); |
| 1556 | kfree(text); | 1647 | kfree(text); |
| 1557 | | 1648 | |
| | 1649 | if (ret == -EOVERFLOW) |
| | 1650 | cs_dsp_err(dsp, "%s: file content overflows file data\n", file); |
| | 1651 | |
| 1558 | return ret; | 1652 | return ret; |
| 1559 | } | 1653 | } |
| 1560 | | 1654 | |
| @@ -2122,10 +2216,20 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware · 561 unmodified lines |
| 2122 | pos = le32_to_cpu(hdr->len); | 2216 | pos = le32_to_cpu(hdr->len); |
| 2123 | | 2217 | |
| 2124 | blocks = 0; | 2218 | blocks = 0; |
| 2125 | while (pos < firmware->size && | 2219 | while (pos < firmware->size) { |
| 2126 | sizeof(*blk) < firmware->size - pos) { | 2220 | /* Is there enough data for a complete block header? */ |
| | 2221 | if (sizeof(*blk) > firmware->size - pos) { |
| | 2222 | ret = -EOVERFLOW; |
| | 2223 | goto out_fw; |
| | 2224 | } |
| | 2225 | |
| 2127 | blk = (void *)(&firmware->data[pos]); | 2226 | blk = (void *)(&firmware->data[pos]); |
| 2128 | | 2227 | |
| | 2228 | if (le32_to_cpu(blk->len) > firmware->size - pos - sizeof(*blk)) { |
| | 2229 | ret = -EOVERFLOW; |
| | 2230 | goto out_fw; |
| | 2231 | } |
| | 2232 | |
| 2129 | type = le16_to_cpu(blk->type); | 2233 | type = le16_to_cpu(blk->type); |
| 2130 | offset = le16_to_cpu(blk->offset); | 2234 | offset = le16_to_cpu(blk->offset); |
| 2131 | version = le32_to_cpu(blk->ver) >> 8; | 2235 | version = le32_to_cpu(blk->ver) >> 8; |
| @@ -2222,17 +2326,6 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware · 90 unmodified lines |
| 2222 | } | 2326 | } |
| 2223 | | 2327 | |
| 2224 | if (reg) { | 2328 | if (reg) { |
| 2225 | if (le32_to_cpu(blk->len) > | | |
| 2226 | firmware->size - pos - sizeof(*blk)) { | | |
| 2227 | cs_dsp_err(dsp, | | |
| 2228 | "%s.%d: %s region len %d bytes exceeds file length %zu\n", | | |
| 2229 | file, blocks, region_name, | | |
| 2230 | le32_to_cpu(blk->len), | | |
| 2231 | firmware->size); | | |
| 2232 | ret = -EINVAL; | | |
| 2233 | goto out_fw; | | |
| 2234 | } | | |
| 2235 | | | |
| 2236 | buf = cs_dsp_buf_alloc(blk->data, | 2329 | buf = cs_dsp_buf_alloc(blk->data, |
| 2237 | le32_to_cpu(blk->len), | 2330 | le32_to_cpu(blk->len), |
| 2238 | &buf_list); | 2331 | &buf_list); |
| @@ -2272,6 +2365,10 @@ out_fw: · 33 unmodified lines |
| 2272 | regmap_async_complete(regmap); | 2365 | regmap_async_complete(regmap); |
| 2273 | cs_dsp_buf_free(&buf_list); | 2366 | cs_dsp_buf_free(&buf_list); |
| 2274 | kfree(text); | 2367 | kfree(text); |
| | 2368 | |
| | 2369 | if (ret == -EOVERFLOW) |
| | 2370 | cs_dsp_err(dsp, "%s: file content overflows file data\n", file); |
| | 2371 | |
| 2275 | return ret; | 2372 | return ret; |
| 2276 | } | 2373 | } |
| 2277 | | 2374 | |