@@ -1053,9 +1053,16 @@ struct cs_dsp_coeff_parsed_coeff {
10531053 int len ;
10541054};
10551055
1056- static int cs_dsp_coeff_parse_string (int bytes , const u8 * * pos , const u8 * * str )
1056+ static int cs_dsp_coeff_parse_string (int bytes , const u8 * * pos , unsigned int avail ,
1057+ const u8 * * str )
10571058{
1058- int length ;
1059+ int length , total_field_len ;
1060+
1061+ /* String fields are at least one __le32 */
1062+ if (sizeof (__le32 ) > avail ) {
1063+ * pos = NULL ;
1064+ return 0 ;
1065+ }
10591066
10601067 switch (bytes ) {
10611068 case 1 :
@@ -1068,10 +1075,16 @@ static int cs_dsp_coeff_parse_string(int bytes, const u8 **pos, const u8 **str)
10681075 return 0 ;
10691076 }
10701077
1078+ total_field_len = ((length + bytes ) + 3 ) & ~0x03 ;
1079+ if ((unsigned int )total_field_len > avail ) {
1080+ * pos = NULL ;
1081+ return 0 ;
1082+ }
1083+
10711084 if (str )
10721085 * str = * pos + bytes ;
10731086
1074- * pos += (( length + bytes ) + 3 ) & ~ 0x03 ;
1087+ * pos += total_field_len ;
10751088
10761089 return length ;
10771090}
@@ -1096,71 +1109,134 @@ static int cs_dsp_coeff_parse_int(int bytes, const u8 **pos)
10961109 return val ;
10971110}
10981111
1099- static inline void cs_dsp_coeff_parse_alg (struct cs_dsp * dsp , const u8 * * data ,
1100- struct cs_dsp_coeff_parsed_alg * blk )
1112+ static int cs_dsp_coeff_parse_alg (struct cs_dsp * dsp ,
1113+ const struct wmfw_region * region ,
1114+ struct cs_dsp_coeff_parsed_alg * blk )
11011115{
11021116 const struct wmfw_adsp_alg_data * raw ;
1117+ unsigned int data_len = le32_to_cpu (region -> len );
1118+ unsigned int pos ;
1119+ const u8 * tmp ;
1120+
1121+ raw = (const struct wmfw_adsp_alg_data * )region -> data ;
11031122
11041123 switch (dsp -> fw_ver ) {
11051124 case 0 :
11061125 case 1 :
1107- raw = ( const struct wmfw_adsp_alg_data * ) * data ;
1108- * data = raw -> data ;
1126+ if ( sizeof ( * raw ) > data_len )
1127+ return - EOVERFLOW ;
11091128
11101129 blk -> id = le32_to_cpu (raw -> id );
11111130 blk -> name = raw -> name ;
11121131 blk -> name_len = strlen (raw -> name );
11131132 blk -> ncoeff = le32_to_cpu (raw -> ncoeff );
1133+
1134+ pos = sizeof (* raw );
11141135 break ;
11151136 default :
1116- blk -> id = cs_dsp_coeff_parse_int (sizeof (raw -> id ), data );
1117- blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), data ,
1137+ if (sizeof (raw -> id ) > data_len )
1138+ return - EOVERFLOW ;
1139+
1140+ tmp = region -> data ;
1141+ blk -> id = cs_dsp_coeff_parse_int (sizeof (raw -> id ), & tmp );
1142+ pos = tmp - region -> data ;
1143+
1144+ tmp = & region -> data [pos ];
1145+ blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , data_len - pos ,
11181146 & blk -> name );
1119- cs_dsp_coeff_parse_string (sizeof (u16 ), data , NULL );
1120- blk -> ncoeff = cs_dsp_coeff_parse_int (sizeof (raw -> ncoeff ), data );
1147+ if (!tmp )
1148+ return - EOVERFLOW ;
1149+
1150+ pos = tmp - region -> data ;
1151+ cs_dsp_coeff_parse_string (sizeof (u16 ), & tmp , data_len - pos , NULL );
1152+ if (!tmp )
1153+ return - EOVERFLOW ;
1154+
1155+ pos = tmp - region -> data ;
1156+ if (sizeof (raw -> ncoeff ) > (data_len - pos ))
1157+ return - EOVERFLOW ;
1158+
1159+ blk -> ncoeff = cs_dsp_coeff_parse_int (sizeof (raw -> ncoeff ), & tmp );
1160+ pos += sizeof (raw -> ncoeff );
11211161 break ;
11221162 }
11231163
1164+ if ((int )blk -> ncoeff < 0 )
1165+ return - EOVERFLOW ;
1166+
11241167 cs_dsp_dbg (dsp , "Algorithm ID: %#x\n" , blk -> id );
11251168 cs_dsp_dbg (dsp , "Algorithm name: %.*s\n" , blk -> name_len , blk -> name );
11261169 cs_dsp_dbg (dsp , "# of coefficient descriptors: %#x\n" , blk -> ncoeff );
1170+
1171+ return pos ;
11271172}
11281173
1129- static inline void cs_dsp_coeff_parse_coeff (struct cs_dsp * dsp , const u8 * * data ,
1130- struct cs_dsp_coeff_parsed_coeff * blk )
1174+ static int cs_dsp_coeff_parse_coeff (struct cs_dsp * dsp ,
1175+ const struct wmfw_region * region ,
1176+ unsigned int pos ,
1177+ struct cs_dsp_coeff_parsed_coeff * blk )
11311178{
11321179 const struct wmfw_adsp_coeff_data * raw ;
1180+ unsigned int data_len = le32_to_cpu (region -> len );
1181+ unsigned int blk_len , blk_end_pos ;
11331182 const u8 * tmp ;
1134- int length ;
1183+
1184+ raw = (const struct wmfw_adsp_coeff_data * )& region -> data [pos ];
1185+ if (sizeof (raw -> hdr ) > (data_len - pos ))
1186+ return - EOVERFLOW ;
1187+
1188+ blk_len = le32_to_cpu (raw -> hdr .size );
1189+ if (blk_len > S32_MAX )
1190+ return - EOVERFLOW ;
1191+
1192+ if (blk_len > (data_len - pos - sizeof (raw -> hdr )))
1193+ return - EOVERFLOW ;
1194+
1195+ blk_end_pos = pos + sizeof (raw -> hdr ) + blk_len ;
1196+
1197+ blk -> offset = le16_to_cpu (raw -> hdr .offset );
1198+ blk -> mem_type = le16_to_cpu (raw -> hdr .type );
11351199
11361200 switch (dsp -> fw_ver ) {
11371201 case 0 :
11381202 case 1 :
1139- raw = ( const struct wmfw_adsp_coeff_data * ) * data ;
1140- * data = * data + sizeof ( raw -> hdr ) + le32_to_cpu ( raw -> hdr . size ) ;
1203+ if ( sizeof ( * raw ) > ( data_len - pos ))
1204+ return - EOVERFLOW ;
11411205
1142- blk -> offset = le16_to_cpu (raw -> hdr .offset );
1143- blk -> mem_type = le16_to_cpu (raw -> hdr .type );
11441206 blk -> name = raw -> name ;
11451207 blk -> name_len = strlen (raw -> name );
11461208 blk -> ctl_type = le16_to_cpu (raw -> ctl_type );
11471209 blk -> flags = le16_to_cpu (raw -> flags );
11481210 blk -> len = le32_to_cpu (raw -> len );
11491211 break ;
11501212 default :
1151- tmp = * data ;
1152- blk -> offset = cs_dsp_coeff_parse_int (sizeof (raw -> hdr .offset ), & tmp );
1153- blk -> mem_type = cs_dsp_coeff_parse_int (sizeof (raw -> hdr .type ), & tmp );
1154- length = cs_dsp_coeff_parse_int (sizeof (raw -> hdr .size ), & tmp );
1155- blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp ,
1213+ pos += sizeof (raw -> hdr );
1214+ tmp = & region -> data [pos ];
1215+ blk -> name_len = cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , data_len - pos ,
11561216 & blk -> name );
1157- cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , NULL );
1158- cs_dsp_coeff_parse_string (sizeof (u16 ), & tmp , NULL );
1217+ if (!tmp )
1218+ return - EOVERFLOW ;
1219+
1220+ pos = tmp - region -> data ;
1221+ cs_dsp_coeff_parse_string (sizeof (u8 ), & tmp , data_len - pos , NULL );
1222+ if (!tmp )
1223+ return - EOVERFLOW ;
1224+
1225+ pos = tmp - region -> data ;
1226+ cs_dsp_coeff_parse_string (sizeof (u16 ), & tmp , data_len - pos , NULL );
1227+ if (!tmp )
1228+ return - EOVERFLOW ;
1229+
1230+ pos = tmp - region -> data ;
1231+ if (sizeof (raw -> ctl_type ) + sizeof (raw -> flags ) + sizeof (raw -> len ) >
1232+ (data_len - pos ))
1233+ return - EOVERFLOW ;
1234+
11591235 blk -> ctl_type = cs_dsp_coeff_parse_int (sizeof (raw -> ctl_type ), & tmp );
1236+ pos += sizeof (raw -> ctl_type );
11601237 blk -> flags = cs_dsp_coeff_parse_int (sizeof (raw -> flags ), & tmp );
1238+ pos += sizeof (raw -> flags );
11611239 blk -> len = cs_dsp_coeff_parse_int (sizeof (raw -> len ), & tmp );
1162-
1163- * data = * data + sizeof (raw -> hdr ) + length ;
11641240 break ;
11651241 }
11661242
@@ -1170,6 +1246,8 @@ static inline void cs_dsp_coeff_parse_coeff(struct cs_dsp *dsp, const u8 **data,
11701246 cs_dsp_dbg (dsp , "\tCoefficient flags: %#x\n" , blk -> flags );
11711247 cs_dsp_dbg (dsp , "\tALSA control type: %#x\n" , blk -> ctl_type );
11721248 cs_dsp_dbg (dsp , "\tALSA control len: %#x\n" , blk -> len );
1249+
1250+ return blk_end_pos ;
11731251}
11741252
11751253static int cs_dsp_check_coeff_flags (struct cs_dsp * dsp ,
@@ -1193,12 +1271,16 @@ static int cs_dsp_parse_coeff(struct cs_dsp *dsp,
11931271 struct cs_dsp_alg_region alg_region = {};
11941272 struct cs_dsp_coeff_parsed_alg alg_blk ;
11951273 struct cs_dsp_coeff_parsed_coeff coeff_blk ;
1196- const u8 * data = region -> data ;
1197- int i , ret ;
1274+ int i , pos , ret ;
1275+
1276+ pos = cs_dsp_coeff_parse_alg (dsp , region , & alg_blk );
1277+ if (pos < 0 )
1278+ return pos ;
11981279
1199- cs_dsp_coeff_parse_alg (dsp , & data , & alg_blk );
12001280 for (i = 0 ; i < alg_blk .ncoeff ; i ++ ) {
1201- cs_dsp_coeff_parse_coeff (dsp , & data , & coeff_blk );
1281+ pos = cs_dsp_coeff_parse_coeff (dsp , region , pos , & coeff_blk );
1282+ if (pos < 0 )
1283+ return pos ;
12021284
12031285 switch (coeff_blk .ctl_type ) {
12041286 case WMFW_CTL_TYPE_BYTES :
0 commit comments