@@ -1107,9 +1107,16 @@ struct cs_dsp_coeff_parsed_coeff {
1107
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
1121
switch (bytes ) {
1115
1122
case 1 :
@@ -1122,10 +1129,16 @@ static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
1122
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
1138
if (str )
1126
1139
* str = * pos + bytes ;
1127
1140
1128
- * pos += (( length + bytes ) + 3 ) & ~ 0x03 ;
1141
+ * pos += total_field_len ;
1129
1142
1130
1143
return length ;
1131
1144
}
@@ -1150,71 +1163,134 @@ static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
1150
1163
return val ;
1151
1164
}
1152
1165
1153
- static inline void cs_dsp_coeff_parse_alg (struct cs_dsp * dsp , const u8 * * data ,
1154
- struct cs_dsp_coeff_parsed_alg * blk )
1166
+ static int cs_dsp_coeff_parse_alg (struct cs_dsp * dsp ,
1167
+ const struct wmfw_region * region ,
1168
+ struct cs_dsp_coeff_parsed_alg * blk )
1155
1169
{
1156
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
1177
switch (dsp -> fw_ver ) {
1159
1178
case 0 :
1160
1179
case 1 :
1161
- raw = ( const struct wmfw_adsp_alg_data * ) * data ;
1162
- * data = raw -> data ;
1180
+ if ( sizeof ( * raw ) > data_len )
1181
+ return - EOVERFLOW ;
1163
1182
1164
1183
blk -> id = le32_to_cpu (raw -> id );
1165
1184
blk -> name = raw -> name ;
1166
- blk -> name_len = strlen (raw -> name );
1185
+ blk -> name_len = strnlen (raw -> name , ARRAY_SIZE ( raw -> name ) );
1167
1186
blk -> ncoeff = le32_to_cpu (raw -> ncoeff );
1187
+
1188
+ pos = sizeof (* raw );
1168
1189
break ;
1169
1190
default :
1170
- blk -> id = cs_dsp_coeff_parse_int (sizeof (raw -> id ), data );
1171
- blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), data ,
1191
+ if (sizeof (raw -> id ) > data_len )
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 = & region -> data [pos ];
1199
+ blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , data_len - pos ,
1172
1200
& blk -> name );
1173
- cs_dsp_coeff_parse_string (sizeof (u16 ), data , NULL );
1174
- blk -> ncoeff = cs_dsp_coeff_parse_int (sizeof (raw -> ncoeff ), data );
1201
+ if (!tmp )
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
1215
break ;
1176
1216
}
1177
1217
1218
+ if ((int )blk -> ncoeff < 0 )
1219
+ return - EOVERFLOW ;
1220
+
1178
1221
cs_dsp_dbg (dsp , "Algorithm ID: %#x\n" , blk -> id );
1179
1222
cs_dsp_dbg (dsp , "Algorithm name: %.*s\n" , blk -> name_len , blk -> name );
1180
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 ,
1184
- struct cs_dsp_coeff_parsed_coeff * blk )
1228
+ static int cs_dsp_coeff_parse_coeff (struct cs_dsp * dsp ,
1229
+ const struct wmfw_region * region ,
1230
+ unsigned int pos ,
1231
+ struct cs_dsp_coeff_parsed_coeff * blk )
1185
1232
{
1186
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
1236
const u8 * tmp ;
1188
- int length ;
1237
+
1238
+ raw = (const struct wmfw_adsp_coeff_data * )& region -> 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
1254
switch (dsp -> fw_ver ) {
1191
1255
case 0 :
1192
1256
case 1 :
1193
- raw = ( const struct wmfw_adsp_coeff_data * ) * data ;
1194
- * data = * data + sizeof ( raw -> hdr ) + le32_to_cpu ( raw -> hdr . size ) ;
1257
+ if ( sizeof ( * raw ) > ( data_len - pos ))
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
1260
blk -> name = raw -> name ;
1199
- blk -> name_len = strlen (raw -> name );
1261
+ blk -> name_len = strnlen (raw -> name , ARRAY_SIZE ( raw -> name ) );
1200
1262
blk -> ctl_type = le16_to_cpu (raw -> ctl_type );
1201
1263
blk -> flags = le16_to_cpu (raw -> flags );
1202
1264
blk -> len = le32_to_cpu (raw -> len );
1203
1265
break ;
1204
1266
default :
1205
- tmp = * data ;
1206
- blk -> offset = cs_dsp_coeff_parse_int (sizeof (raw -> hdr .offset ), & tmp );
1207
- blk -> mem_type = cs_dsp_coeff_parse_int (sizeof (raw -> hdr .type ), & tmp );
1208
- length = cs_dsp_coeff_parse_int (sizeof (raw -> hdr .size ), & tmp );
1209
- blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp ,
1267
+ pos += sizeof (raw -> hdr );
1268
+ tmp = & region -> data [pos ];
1269
+ blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , data_len - pos ,
1210
1270
& blk -> name );
1211
- cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , NULL );
1212
- cs_dsp_coeff_parse_string (sizeof (u16 ), & tmp , NULL );
1271
+ if (!tmp )
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
1289
blk -> ctl_type = cs_dsp_coeff_parse_int (sizeof (raw -> ctl_type ), & tmp );
1290
+ pos += sizeof (raw -> ctl_type );
1214
1291
blk -> flags = cs_dsp_coeff_parse_int (sizeof (raw -> flags ), & tmp );
1292
+ pos += sizeof (raw -> flags );
1215
1293
blk -> len = cs_dsp_coeff_parse_int (sizeof (raw -> len ), & tmp );
1216
-
1217
- * data = * data + sizeof (raw -> hdr ) + length ;
1218
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,
1224
1300
cs_dsp_dbg (dsp , "\tCoefficient flags: %#x\n" , blk -> flags );
1225
1301
cs_dsp_dbg (dsp , "\tALSA control type: %#x\n" , blk -> ctl_type );
1226
1302
cs_dsp_dbg (dsp , "\tALSA control len: %#x\n" , blk -> len );
1303
+
1304
+ return blk_end_pos ;
1227
1305
}
1228
1306
1229
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,
1247
1325
struct cs_dsp_alg_region alg_region = {};
1248
1326
struct cs_dsp_coeff_parsed_alg alg_blk ;
1249
1327
struct cs_dsp_coeff_parsed_coeff coeff_blk ;
1250
- const u8 * data = region -> data ;
1251
- int i , ret ;
1328
+ int i , pos , 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
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
1339
switch (coeff_blk .ctl_type ) {
1258
1340
case WMFW_CTL_TYPE_BYTES :
@@ -1321,6 +1403,10 @@ static unsigned int cs_dsp_adsp1_parse_sizes(struct cs_dsp *dsp,
1321
1403
const struct wmfw_adsp1_sizes * adsp1_sizes ;
1322
1404
1323
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
1411
cs_dsp_dbg (dsp , "%s: %d DM, %d PM, %d ZM\n" , file ,
1326
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,
1337
1423
const struct wmfw_adsp2_sizes * adsp2_sizes ;
1338
1424
1339
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
1431
cs_dsp_dbg (dsp , "%s: %d XM, %d YM %d PM, %d ZM\n" , file ,
1342
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,
1376
1466
struct regmap * regmap = dsp -> regmap ;
1377
1467
unsigned int pos = 0 ;
1378
1468
const struct wmfw_header * header ;
1379
- const struct wmfw_adsp1_sizes * adsp1_sizes ;
1380
1469
const struct wmfw_footer * footer ;
1381
1470
const struct wmfw_region * region ;
1382
1471
const struct cs_dsp_region * mem ;
@@ -1392,10 +1481,8 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
1392
1481
1393
1482
ret = - EINVAL ;
1394
1483
1395
- pos = sizeof (* header ) + sizeof (* adsp1_sizes ) + sizeof (* footer );
1396
- if (pos >= firmware -> size ) {
1397
- cs_dsp_err (dsp , "%s: file too short, %zu bytes\n" ,
1398
- file , firmware -> size );
1484
+ if (sizeof (* header ) >= firmware -> size ) {
1485
+ ret = - EOVERFLOW ;
1399
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,
1423
1510
1424
1511
pos = sizeof (* header );
1425
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
1518
footer = (void * )& firmware -> data [pos ];
1428
1519
pos += sizeof (* footer );
1429
1520
1430
1521
if (le32_to_cpu (header -> len ) != pos ) {
1431
- cs_dsp_err (dsp , "%s: unexpected header length %d\n" ,
1432
- file , le32_to_cpu (header -> len ));
1522
+ ret = - EOVERFLOW ;
1433
1523
goto out_fw ;
1434
1524
}
1435
1525
1436
1526
cs_dsp_dbg (dsp , "%s: timestamp %llu\n" , file ,
1437
1527
le64_to_cpu (footer -> timestamp ));
1438
1528
1439
- while (pos < firmware -> size &&
1440
- sizeof (* region ) < firmware -> size - pos ) {
1529
+ while (pos < firmware -> size ) {
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
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
1543
region_name = "Unknown" ;
1443
1544
reg = 0 ;
1444
1545
text = NULL ;
@@ -1495,16 +1596,6 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
1495
1596
regions , le32_to_cpu (region -> len ), offset ,
1496
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
1599
if (text ) {
1509
1600
memcpy (text , region -> data , le32_to_cpu (region -> len ));
1510
1601
cs_dsp_info (dsp , "%s: %s\n" , file , text );
@@ -1555,6 +1646,9 @@ static int cs_dsp_load(struct cs_dsp *dsp, const struct firmware *firmware,
1555
1646
cs_dsp_buf_free (& buf_list );
1556
1647
kfree (text );
1557
1648
1649
+ if (ret == - EOVERFLOW )
1650
+ cs_dsp_err (dsp , "%s: file content overflows file data\n" , file );
1651
+
1558
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
2122
2216
pos = le32_to_cpu (hdr -> len );
2123
2217
2124
2218
blocks = 0 ;
2125
- while (pos < firmware -> size &&
2126
- sizeof (* blk ) < firmware -> size - pos ) {
2219
+ while (pos < firmware -> size ) {
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
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
2233
type = le16_to_cpu (blk -> type );
2130
2234
offset = le16_to_cpu (blk -> offset );
2131
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
2222
2326
}
2223
2327
2224
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
2329
buf = cs_dsp_buf_alloc (blk -> data ,
2237
2330
le32_to_cpu (blk -> len ),
2238
2331
& buf_list );
@@ -2272,6 +2365,10 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
2272
2365
regmap_async_complete (regmap );
2273
2366
cs_dsp_buf_free (& buf_list );
2274
2367
kfree (text );
2368
+
2369
+ if (ret == - EOVERFLOW )
2370
+ cs_dsp_err (dsp , "%s: file content overflows file data\n" , file );
2371
+
2275
2372
return ret ;
2276
2373
}
2277
2374
0 commit comments