Bluetooth: btintel: Add infrastructure to read controller information
Hello Kiran K,
The patch 57375beef71a: "Bluetooth: btintel: Add infrastructure to read controller information" from Sep 14, 2020, leads to the following static checker warning:
drivers/bluetooth/btintel.c:490 btintel_read_version_tlv() error: 'tlv->len' from user is not capped properly
drivers/bluetooth/btintel.c
426 /* Consume Command Complete Status field */
427 skb_pull(skb, 1);
428
429 /* Event parameters contatin multiple TLVs. Read each of them
430 * and only keep the required data. Also, it use existing legacy
431 * version field like hw_platform, hw_variant, and fw_variant
432 * to keep the existing setup flow
433 */
434 while (skb->len) {
^^^^^^^^I feel like these days we are trying to not trust firmware... Smatch is complaining because it distrusts all skb->data information, but unless the devs at Google have a way to connect a fuzzer to this then trusting is probably harmless. Anyway, the rest of this email assumes that fuzzing is possible.
If skb->len is less than sizeof(*tlv) then it will read beyond the end of the skb.
while (skb->len >= sizeof(struct intel_tlv)) {
But struct intel_tlv is variable length so it's more complicated than just testing while we need aditional tests below.
435 struct intel_tlv *tlv; 436 437 tlv = (struct intel_tlv *)skb->data;
if (struct_size(tlv->len, val, tvl) > skb->len)
return -EINVAL;
The length has to be at least 1.
if (tvl->len < 1)
return -EINVAL;
438 switch (tlv->type) {
439 case INTEL_TLV_CNVI_TOP:Ever test which is reads more than 1 byte has to have a check:
if (tvl->len < sizeof(u32))
return -EINVAL;
440 version->cnvi_top = get_unaligned_le32(tlv->val); 441 break; 442 case INTEL_TLV_CNVR_TOP:
Here too, etc.
443 version->cnvr_top = get_unaligned_le32(tlv->val); 444 break; 445 case INTEL_TLV_CNVI_BT: 446 version->cnvi_bt = get_unaligned_le32(tlv->val); 447 break; 448 case INTEL_TLV_CNVR_BT: 449 version->cnvr_bt = get_unaligned_le32(tlv->val); 450 break; 451 case INTEL_TLV_DEV_REV_ID: 452 version->dev_rev_id = get_unaligned_le16(tlv->val); 453 break; 454 case INTEL_TLV_IMAGE_TYPE: 455 version->img_type = tlv->val[0]; 456 break; 457 case INTEL_TLV_TIME_STAMP:
if (tvl->len < sizeof(u16))
return -EINVAL;
458 version->timestamp = get_unaligned_le16(tlv->val); 459 break; 460 case INTEL_TLV_BUILD_TYPE: 461 version->build_type = tlv->val[0]; 462 break; 463 case INTEL_TLV_BUILD_NUM: 464 version->build_num = get_unaligned_le32(tlv->val); 465 break; 466 case INTEL_TLV_SECURE_BOOT: 467 version->secure_boot = tlv->val[0]; 468 break; 469 case INTEL_TLV_OTP_LOCK: 470 version->otp_lock = tlv->val[0]; 471 break; 472 case INTEL_TLV_API_LOCK: 473 version->api_lock = tlv->val[0]; 474 break; 475 case INTEL_TLV_DEBUG_LOCK: 476 version->debug_lock = tlv->val[0]; 477 break; 478 case INTEL_TLV_MIN_FW:
if (tvl->len < 3)
return -EINVAL;
479 version->min_fw_build_nn = tlv->val[0];
480 version->min_fw_build_cw = tlv->val[1];
481 version->min_fw_build_yy = tlv->val[2];
482 break;
483 case INTEL_TLV_LIMITED_CCE:
484 version->limited_cce = tlv->val[0];
485 break;
486 case INTEL_TLV_SBE_TYPE:
487 version->sbe_type = tlv->val[0];
488 break;
489 case INTEL_TLV_OTP_BDADDR:
490 memcpy(&version->otp_bd_addr, tlv->val, tlv->len);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^tlv->len comes from the network and it's 0-255. If it's more than 6 then this will corrupt memory. There is no caller for this function yet in linux-next so if tvl->len is less than 6 will that leave uninitialized memory in ->otp_bd_addr?
if (tlv->len != sizeof(version->otp_bd_addr)) return -EINVAL;
491 break; 492 default: 493 /* Ignore rest of information */ 494 break; 495 } 496 /* consume the current tlv and move to next*/ 497 skb_pull(skb, tlv->len + sizeof(*tlv)); 498 } 499 500 kfree_skb(skb); 501 return 0;
regards,
dan carpenter
Hi Dan,
Thanks for the comments. For some reason, the static analysis tool I am using didn't report these issues. I will submit a patch soon to address these issues.
Regards,
Kiran
Quoted 146 lines
-----Original Message-----
From: Dan Carpenter <[email protected]>
Sent: Friday, September 18, 2020 3:09 PM
To: [email protected]
Cc: [email protected]
Subject: [bug report] Bluetooth: btintel: Add infrastructure to read controller informationHello Kiran K,
The patch
57375beef71a: "Bluetooth: btintel: Add infrastructure to read controller information" from Sep 14, 2020, leads to the following static checker warning:drivers/bluetooth/btintel.c:490 btintel_read_version_tlv() error: 'tlv->len' from user is not capped properly
drivers/bluetooth/btintel.c
426 /* Consume Command Complete Status field */
427skb_pull(skb, 1);
428
429 /* Event parameters contatin multiple TLVs. Read each of them430 * and only keep the required data. Also, it use existing legacy 431 * version field like hw_platform, hw_variant, and fw_variant 432 * to keep the existing setup flow 433 */ 434 while (skb->len) { ^^^^^^^^I feel like these days we are trying to not trust firmware... Smatch is complaining because it distrusts all
skb->datainformation, but unless the devs at Google have a way to connect a fuzzer to this then trusting is probably harmless. Anyway, the rest of this email assumes that fuzzing is possible.If
skb->lenis less thansizeof(*tlv)then it will read beyond the end of the skb.while (
skb->len>=sizeof(struct intel_tlv)) {But struct
intel_tlvis variable length so it's more complicated than just testing while we need aditional tests below.435 struct intel_tlv *tlv; 436 437 tlv = (struct intel_tlv *)skb->data;if (
struct_size(tlv->len, val, tvl)>skb->len)return -EINVAL;The length has to be at least 1.
if (
tvl->len< 1)return -EINVAL;438 switch (tlv->type) { 439 case INTEL_TLV_CNVI_TOP:Ever test which is reads more than 1 byte has to have a check:
if (
tvl->len< sizeof(u32))return -EINVAL;440 version->cnvi_top = get_unaligned_le32(tlv->val); 441 break; 442 case INTEL_TLV_CNVR_TOP:Here too, etc.
443 version->cnvr_top = get_unaligned_le32(tlv->val); 444 break; 445 case INTEL_TLV_CNVI_BT: 446 version->cnvi_bt = get_unaligned_le32(tlv->val); 447 break; 448 case INTEL_TLV_CNVR_BT: 449 version->cnvr_bt = get_unaligned_le32(tlv->val); 450 break; 451 case INTEL_TLV_DEV_REV_ID: 452 version->dev_rev_id = get_unaligned_le16(tlv->val); 453 break; 454 case INTEL_TLV_IMAGE_TYPE: 455 version->img_type = tlv->val[0]; 456 break; 457 case INTEL_TLV_TIME_STAMP:if (
tvl->len< sizeof(u16))return -EINVAL;458 version->timestamp = get_unaligned_le16(tlv->val); 459 break; 460 case INTEL_TLV_BUILD_TYPE: 461 version->build_type = tlv->val[0]; 462 break; 463 case INTEL_TLV_BUILD_NUM: 464 version->build_num = get_unaligned_le32(tlv->val); 465 break; 466 case INTEL_TLV_SECURE_BOOT: 467 version->secure_boot = tlv->val[0]; 468 break; 469 case INTEL_TLV_OTP_LOCK: 470 version->otp_lock = tlv->val[0]; 471 break; 472 case INTEL_TLV_API_LOCK: 473 version->api_lock = tlv->val[0]; 474 break; 475 case INTEL_TLV_DEBUG_LOCK: 476 version->debug_lock = tlv->val[0]; 477 break; 478 case INTEL_TLV_MIN_FW:if (
tvl->len< 3)return -EINVAL;479 version->min_fw_build_nn = tlv->val[0]; 480 version->min_fw_build_cw = tlv->val[1]; 481 version->min_fw_build_yy = tlv->val[2]; 482 break; 483 case INTEL_TLV_LIMITED_CCE: 484 version->limited_cce = tlv->val[0]; 485 break; 486 case INTEL_TLV_SBE_TYPE: 487 version->sbe_type = tlv->val[0]; 488 break; 489 case INTEL_TLV_OTP_BDADDR: 490 memcpy(&version->otp_bd_addr, tlv->val, tlv->len); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
tlv->lencomes from the network and it's 0-255. If it's more than 6 then this will corrupt memory. There is no caller for this function yet in linux- next so iftvl->lenis less than 6 will that leave uninitialized memory in -Quoted 1 line
otp_bd_addr?if (tlv->len != sizeof(version->otp_bd_addr)) return -EINVAL;491 break; 492 default: 493 /* Ignore rest of information */ 494 break; 495 } 496 /* consume the current tlv and move to next*/ 497 skb_pull(skb, tlv->len + sizeof(*tlv)); 498 } 499 500 kfree_skb(skb); 501 return 0;regards,
dan carpenter