@@ -268,9 +268,10 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
268268}
269269EXPORT_SYMBOL_GPL (qca_send_pre_shutdown_cmd );
270270
271- static void qca_tlv_check_data (struct hci_dev * hdev ,
271+ static int qca_tlv_check_data (struct hci_dev * hdev ,
272272 struct qca_fw_config * config ,
273- u8 * fw_data , enum qca_btsoc_type soc_type )
273+ u8 * fw_data , size_t fw_size ,
274+ enum qca_btsoc_type soc_type )
274275{
275276 const u8 * data ;
276277 u32 type_len ;
@@ -286,6 +287,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
286287
287288 switch (config -> type ) {
288289 case ELF_TYPE_PATCH :
290+ if (fw_size < 7 )
291+ return - EINVAL ;
292+
289293 config -> dnld_mode = QCA_SKIP_EVT_VSE_CC ;
290294 config -> dnld_type = QCA_SKIP_EVT_VSE_CC ;
291295
@@ -294,6 +298,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
294298 bt_dev_dbg (hdev , "File version : 0x%x" , fw_data [6 ]);
295299 break ;
296300 case TLV_TYPE_PATCH :
301+ if (fw_size < sizeof (struct tlv_type_hdr ) + sizeof (struct tlv_type_patch ))
302+ return - EINVAL ;
303+
297304 tlv = (struct tlv_type_hdr * )fw_data ;
298305 type_len = le32_to_cpu (tlv -> type_len );
299306 tlv_patch = (struct tlv_type_patch * )tlv -> data ;
@@ -333,6 +340,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
333340 break ;
334341
335342 case TLV_TYPE_NVM :
343+ if (fw_size < sizeof (struct tlv_type_hdr ))
344+ return - EINVAL ;
345+
336346 tlv = (struct tlv_type_hdr * )fw_data ;
337347
338348 type_len = le32_to_cpu (tlv -> type_len );
@@ -341,17 +351,26 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
341351 BT_DBG ("TLV Type\t\t : 0x%x" , type_len & 0x000000ff );
342352 BT_DBG ("Length\t\t : %d bytes" , length );
343353
354+ if (fw_size < length + (tlv -> data - fw_data ))
355+ return - EINVAL ;
356+
344357 idx = 0 ;
345358 data = tlv -> data ;
346- while (idx < length ) {
359+ while (idx < length - sizeof ( struct tlv_type_nvm ) ) {
347360 tlv_nvm = (struct tlv_type_nvm * )(data + idx );
348361
349362 tag_id = le16_to_cpu (tlv_nvm -> tag_id );
350363 tag_len = le16_to_cpu (tlv_nvm -> tag_len );
351364
365+ if (length < idx + sizeof (struct tlv_type_nvm ) + tag_len )
366+ return - EINVAL ;
367+
352368 /* Update NVM tags as needed */
353369 switch (tag_id ) {
354370 case EDL_TAG_ID_HCI :
371+ if (tag_len < 3 )
372+ return - EINVAL ;
373+
355374 /* HCI transport layer parameters
356375 * enabling software inband sleep
357376 * onto controller side.
@@ -367,6 +386,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
367386 break ;
368387
369388 case EDL_TAG_ID_DEEP_SLEEP :
389+ if (tag_len < 1 )
390+ return - EINVAL ;
391+
370392 /* Sleep enable mask
371393 * enabling deep sleep feature on controller.
372394 */
@@ -375,14 +397,16 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
375397 break ;
376398 }
377399
378- idx += ( sizeof (u16 ) + sizeof ( u16 ) + 8 + tag_len ) ;
400+ idx += sizeof (struct tlv_type_nvm ) + tag_len ;
379401 }
380402 break ;
381403
382404 default :
383405 BT_ERR ("Unknown TLV type %d" , config -> type );
384- break ;
406+ return - EINVAL ;
385407 }
408+
409+ return 0 ;
386410}
387411
388412static int qca_tlv_send_segment (struct hci_dev * hdev , int seg_size ,
@@ -532,7 +556,9 @@ static int qca_download_firmware(struct hci_dev *hdev,
532556 memcpy (data , fw -> data , size );
533557 release_firmware (fw );
534558
535- qca_tlv_check_data (hdev , config , data , soc_type );
559+ ret = qca_tlv_check_data (hdev , config , data , size , soc_type );
560+ if (ret )
561+ return ret ;
536562
537563 segment = data ;
538564 remain = size ;
0 commit comments