RE: [bug report] Bluetooth: btintel: Add infrastructure to read controller information

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

> -----Original Message-----
> From: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
> Sent: Friday, September 18, 2020 3:09 PM
> To: kiraank@xxxxxxxxx
> Cc: linux-bluetooth@xxxxxxxxxxxxxxx
> Subject: [bug report] 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




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux