Re: [PATCH v1] Bluetooth: btintel: Fix issue reported by static analysis tool

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

 



Hi Kiran,

>>> Smatch tool reported the below issue:
>>> 
>>> drivers/bluetooth/btintel.c:490 btintel_read_version_tlv()
>>> error: 'tlv->len' from user is not capped properly
>>> 
>>> Additional details in the below link
>>> https://www.spinics.net/lists/linux-bluetooth/msg87786.html
>>> 
>>> Signed-off-by: Kiran K <kiran.k@xxxxxxxxx>
>>> ---
>>> drivers/bluetooth/btintel.c | 43
>>> ++++++++++++++++++++++++++++++++++++++++++-
>>> 1 file changed, 42 insertions(+), 1 deletion(-)
>>> 
>>> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
>>> index 88ce5f0..47f2b3d 100644
>>> --- a/drivers/bluetooth/btintel.c
>>> +++ b/drivers/bluetooth/btintel.c
>>> @@ -431,62 +431,99 @@ int btintel_read_version_tlv(struct hci_dev
>> *hdev, struct intel_version_tlv *ver
>>>         * version field like hw_platform, hw_variant, and fw_variant
>>>         * to keep the existing setup flow
>>>         */
>>> -       while (skb->len) {
>>> +       while (skb->len >= sizeof(struct intel_tlv)) {
>>>                struct intel_tlv *tlv;
>>> 
>>>                tlv = (struct intel_tlv *)skb->data;
>>> +               if (struct_size(tlv, val, tlv->len) > skb->len)
>>> +                       goto failed;
>>> +
>>>                switch (tlv->type) {
>>>                case INTEL_TLV_CNVI_TOP:
>>> +                       if (tlv->len < sizeof(u32))
>>> +                               goto failed;
>>>                        version->cnvi_top = get_unaligned_le32(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_CNVR_TOP:
>>> +                       if (tlv->len < sizeof(u32))
>>> +                               goto failed;
>>>                        version->cnvr_top = get_unaligned_le32(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_CNVI_BT:
>>> +                       if (tlv->len < sizeof(u32))
>>> +                               goto failed;
>>>                        version->cnvi_bt = get_unaligned_le32(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_CNVR_BT:
>>> +                       if (tlv->len < sizeof(u32))
>>> +                               goto failed;
>>>                        version->cnvr_bt = get_unaligned_le32(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_DEV_REV_ID:
>>> +                       if (tlv->len < sizeof(u16))
>>> +                               goto failed;
>>>                        version->dev_rev_id = get_unaligned_le16(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_IMAGE_TYPE:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->img_type = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_TIME_STAMP:
>>> +                       if (tlv->len < sizeof(u16))
>>> +                               goto failed;
>>>                        version->timestamp = get_unaligned_le16(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_BUILD_TYPE:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->build_type = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_BUILD_NUM:
>>> +                       if (tlv->len < sizeof(u32))
>>> +                               goto failed;
>>>                        version->build_num = get_unaligned_le32(tlv->val);
>>>                        break;
>>>                case INTEL_TLV_SECURE_BOOT:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->secure_boot = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_OTP_LOCK:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->otp_lock = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_API_LOCK:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->api_lock = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_DEBUG_LOCK:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->debug_lock = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_MIN_FW:
>>> +                       if (tlv->len < 3)
>>> +                               goto failed;
>>>                        version->min_fw_build_nn = tlv->val[0];
>>>                        version->min_fw_build_cw = tlv->val[1];
>>>                        version->min_fw_build_yy = tlv->val[2];
>>>                        break;
>>>                case INTEL_TLV_LIMITED_CCE:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->limited_cce = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_SBE_TYPE:
>>> +                       if (tlv->len < sizeof(u8))
>>> +                               goto failed;
>>>                        version->sbe_type = tlv->val[0];
>>>                        break;
>>>                case INTEL_TLV_OTP_BDADDR:
>>> +                       if (tlv->len != sizeof(version->otp_bd_addr))
>>> +                               goto failed;
>> 
>> Do we really want to fail here? The advantage of using a TLV is that we can
>> skip if the type is not understood or is malformed but with this checks the
>> length becomes useless since the types will always have a fixed value, also
> 
> Agree that the types are fixed here. But if due to some reason if controller is not honoring the same, then driver might end up reading unwanted data. The check is more about driver being defensive rather than believing  what comes on wire.
> 
>> we cannot extend the types later on since it would not be backward
>> compatible if we maintain such strict checks.
> 
> I didn’t get this part. Could you please be more specific ?

please change this that you check the size of the TLV data part against the expected size of the field and only then assign it.

Regards

Marcel




[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