@@ -1107,9 +1107,16 @@ struct cs_dsp_coeff_parsed_coeff {
11071107 int len ;
11081108};
11091109
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 )
11111112{
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+ }
11131120
11141121 switch (bytes ) {
11151122 case 1 :
@@ -1122,10 +1129,16 @@ static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
11221129 return 0 ;
11231130 }
11241131
1132+ total_field_len = ((length + bytes ) + 3 ) & ~0x03 ;
1133+ if ((unsigned int )total_field_len > avail ) {
1134+ * pos = NULL ;
1135+ return 0 ;
1136+ }
1137+
11251138 if (str )
11261139 * str = * pos + bytes ;
11271140
1128- * pos += (( length + bytes ) + 3 ) & ~ 0x03 ;
1141+ * pos += total_field_len ;
11291142
11301143 return length ;
11311144}
@@ -1150,71 +1163,134 @@ static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
11501163 return val ;
11511164}
11521165
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 )
11551169{
11561170 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 ;
11571176
11581177 switch (dsp -> fw_ver ) {
11591178 case 0 :
11601179 case 1 :
1161- raw = ( const struct wmfw_adsp_alg_data * ) * data ;
1162- * data = raw -> data ;
1180+ if ( sizeof ( * raw ) > data_len )
1181+ return - EOVERFLOW ;
11631182
11641183 blk -> id = le32_to_cpu (raw -> id );
11651184 blk -> name = raw -> name ;
11661185 blk -> name_len = strlen (raw -> name );
11671186 blk -> ncoeff = le32_to_cpu (raw -> ncoeff );
1187+
1188+ pos = sizeof (* raw );
11681189 break ;
11691190 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 ,
11721200 & 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 );
11751215 break ;
11761216 }
11771217
1218+ if ((int )blk -> ncoeff < 0 )
1219+ return - EOVERFLOW ;
1220+
11781221 cs_dsp_dbg (dsp , "Algorithm ID: %#x\n" , blk -> id );
11791222 cs_dsp_dbg (dsp , "Algorithm name: %.*s\n" , blk -> name_len , blk -> name );
11801223 cs_dsp_dbg (dsp , "# of coefficient descriptors: %#x\n" , blk -> ncoeff );
1224+
1225+ return pos ;
11811226}
11821227
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 )
11851232{
11861233 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 ;
11871236 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 );
11891253
11901254 switch (dsp -> fw_ver ) {
11911255 case 0 :
11921256 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 ;
11951259
1196- blk -> offset = le16_to_cpu (raw -> hdr .offset );
1197- blk -> mem_type = le16_to_cpu (raw -> hdr .type );
11981260 blk -> name = raw -> name ;
11991261 blk -> name_len = strlen (raw -> name );
12001262 blk -> ctl_type = le16_to_cpu (raw -> ctl_type );
12011263 blk -> flags = le16_to_cpu (raw -> flags );
12021264 blk -> len = le32_to_cpu (raw -> len );
12031265 break ;
12041266 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 ,
12101270 & 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+
12131289 blk -> ctl_type = cs_dsp_coeff_parse_int (sizeof (raw -> ctl_type ), & tmp );
1290+ pos += sizeof (raw -> ctl_type );
12141291 blk -> flags = cs_dsp_coeff_parse_int (sizeof (raw -> flags ), & tmp );
1292+ pos += sizeof (raw -> flags );
12151293 blk -> len = cs_dsp_coeff_parse_int (sizeof (raw -> len ), & tmp );
1216-
1217- * data = * data + sizeof (raw -> hdr ) + length ;
12181294 break ;
12191295 }
12201296
@@ -1224,6 +1300,8 @@ static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data,
12241300 cs_dsp_dbg (dsp , "\tCoefficient flags: %#x\n" , blk -> flags );
12251301 cs_dsp_dbg (dsp , "\tALSA control type: %#x\n" , blk -> ctl_type );
12261302 cs_dsp_dbg (dsp , "\tALSA control len: %#x\n" , blk -> len );
1303+
1304+ return blk_end_pos ;
12271305}
12281306
12291307static int cs_dsp_check_coeff_flags (struct cs_dsp * dsp ,
@@ -1247,12 +1325,16 @@ static int cs_dsp_parse_coeff(struct cs_dsp *dsp,
12471325 struct cs_dsp_alg_region alg_region = {};
12481326 struct cs_dsp_coeff_parsed_alg alg_blk ;
12491327 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 ;
12521333
1253- cs_dsp_coeff_parse_alg (dsp , & data , & alg_blk );
12541334 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 ;
12561338
12571339 switch (coeff_blk .ctl_type ) {
12581340 case WMFW_CTL_TYPE_BYTES :
0 commit comments