@@ -268,9 +268,10 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
268
268
}
269
269
EXPORT_SYMBOL_GPL (qca_send_pre_shutdown_cmd );
270
270
271
- static void qca_tlv_check_data (struct hci_dev * hdev ,
271
+ static int qca_tlv_check_data (struct hci_dev * hdev ,
272
272
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 )
274
275
{
275
276
const u8 * data ;
276
277
u32 type_len ;
@@ -286,6 +287,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
286
287
287
288
switch (config -> type ) {
288
289
case ELF_TYPE_PATCH :
290
+ if (fw_size < 7 )
291
+ return - EINVAL ;
292
+
289
293
config -> dnld_mode = QCA_SKIP_EVT_VSE_CC ;
290
294
config -> dnld_type = QCA_SKIP_EVT_VSE_CC ;
291
295
@@ -294,6 +298,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
294
298
bt_dev_dbg (hdev , "File version : 0x%x" , fw_data [6 ]);
295
299
break ;
296
300
case TLV_TYPE_PATCH :
301
+ if (fw_size < sizeof (struct tlv_type_hdr ) + sizeof (struct tlv_type_patch ))
302
+ return - EINVAL ;
303
+
297
304
tlv = (struct tlv_type_hdr * )fw_data ;
298
305
type_len = le32_to_cpu (tlv -> type_len );
299
306
tlv_patch = (struct tlv_type_patch * )tlv -> data ;
@@ -333,6 +340,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
333
340
break ;
334
341
335
342
case TLV_TYPE_NVM :
343
+ if (fw_size < sizeof (struct tlv_type_hdr ))
344
+ return - EINVAL ;
345
+
336
346
tlv = (struct tlv_type_hdr * )fw_data ;
337
347
338
348
type_len = le32_to_cpu (tlv -> type_len );
@@ -341,17 +351,26 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
341
351
BT_DBG ("TLV Type\t\t : 0x%x" , type_len & 0x000000ff );
342
352
BT_DBG ("Length\t\t : %d bytes" , length );
343
353
354
+ if (fw_size < length + (tlv -> data - fw_data ))
355
+ return - EINVAL ;
356
+
344
357
idx = 0 ;
345
358
data = tlv -> data ;
346
- while (idx < length ) {
359
+ while (idx < length - sizeof ( struct tlv_type_nvm ) ) {
347
360
tlv_nvm = (struct tlv_type_nvm * )(data + idx );
348
361
349
362
tag_id = le16_to_cpu (tlv_nvm -> tag_id );
350
363
tag_len = le16_to_cpu (tlv_nvm -> tag_len );
351
364
365
+ if (length < idx + sizeof (struct tlv_type_nvm ) + tag_len )
366
+ return - EINVAL ;
367
+
352
368
/* Update NVM tags as needed */
353
369
switch (tag_id ) {
354
370
case EDL_TAG_ID_HCI :
371
+ if (tag_len < 3 )
372
+ return - EINVAL ;
373
+
355
374
/* HCI transport layer parameters
356
375
* enabling software inband sleep
357
376
* onto controller side.
@@ -367,6 +386,9 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
367
386
break ;
368
387
369
388
case EDL_TAG_ID_DEEP_SLEEP :
389
+ if (tag_len < 1 )
390
+ return - EINVAL ;
391
+
370
392
/* Sleep enable mask
371
393
* enabling deep sleep feature on controller.
372
394
*/
@@ -375,14 +397,16 @@ static void qca_tlv_check_data(struct hci_dev *hdev,
375
397
break ;
376
398
}
377
399
378
- idx += ( sizeof (u16 ) + sizeof ( u16 ) + 8 + tag_len ) ;
400
+ idx += sizeof (struct tlv_type_nvm ) + tag_len ;
379
401
}
380
402
break ;
381
403
382
404
default :
383
405
BT_ERR ("Unknown TLV type %d" , config -> type );
384
- break ;
406
+ return - EINVAL ;
385
407
}
408
+
409
+ return 0 ;
386
410
}
387
411
388
412
static 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,
532
556
memcpy (data , fw -> data , size );
533
557
release_firmware (fw );
534
558
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 ;
536
562
537
563
segment = data ;
538
564
remain = size ;
0 commit comments