Skip to content

Conversation

lylezhu2012
Copy link
Contributor

@lylezhu2012 lylezhu2012 commented Aug 25, 2025

In function parse_read_by_uuid(), the response length is not checked before parsing the response PDU. There is a potential issue that the len will be underflowed if the len is less than the size of struct bt_att_data.

Check the length before parsing the response PDU. If the length is less then the size of struct bt_att_data, notify the upper layer with the error BT_ATT_ERR_INVALID_PDU and stop the parsing.

@@ -4761,6 +4761,15 @@ static void parse_read_by_uuid(struct bt_conn *conn,
uint16_t handle;
uint16_t len;

len = MIN(rsp->len, length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the MIN here?

Don't we need to modify the

for (length--, pdu = rsp->data; length;
length -= rsp->len, pdu = (const uint8_t *)pdu + rsp->len) {

as well? This assumes that length -= rsp->len is always valid, but if length = 10 and rsp->len = 13 (invalid response length), then that will still be an invalid operation, right?

Copy link
Contributor Author

@lylezhu2012 lylezhu2012 Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the MIN here?

The original equation is len = rsp->len > length ? length - 2 : rsp->len - 2;.

It is equal to len = MIN(rsp->len, length) - 2;.

This assumes that length -= rsp->len is always valid, but if length = 10 and rsp->len = 13 (invalid response length), then that will still be an invalid operation, right?

It will be checked here,

/* Check if long attribute */
if (rsp->len > length) {
break;
}

@lylezhu2012 lylezhu2012 force-pushed the Fix_gatt_coverity_issue branch from fb96b71 to b85c500 Compare August 25, 2025 07:06
len = MIN(rsp->len, length);
if (len < sizeof(struct bt_att_data)) {
LOG_WRN("Bad peer: ATT read-by-uuid rsp: invalid ATTR data len %u", len);
params->func(conn, BT_ATT_ERR_INVALID_ATTRIBUTE_LEN, params, NULL, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not BT_ATT_ERR_INVALID_PDU? Doesn't this mean that ATT PDU is malformed?

It is even a question if we are allowed to use response error codes here as it may look like server's response error. But doesn't seem that spec defines behavior for such case unless I'm missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not BT_ATT_ERR_INVALID_PDU? Doesn't this mean that ATT PDU is malformed?

Is it possible that the peer device is malfunctioning, or is it a malicious device? The peer device does this intentionally.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BT_ATT_ERR_INVALID_PDU might actually be a better error code, as it indeed an invalid PDU

It is even a question if we are allowed to use response error codes here as it may look like server's response error. But doesn't seem that spec defines behavior for such case unless I'm missing something.

I tend to agree with this, but it also seems like something we do quite a lot in Zephyr. If the err parameter of the callback was a int instead of uint8_t we could have defined it as 0 => success, > 0 => ATT error, < 0 => local error, but that'd be an API change

Copy link
Contributor

@PavelVPV PavelVPV Aug 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of peer's intention, the ATT PDU is not correctly formed. struct bt_att_data is 2 bytes long (added) representing only 16-bit handle. If the response has 1 byte left (half of ATT opcode attribute handle), is this invalid attribute length or PDU?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected myself: ATT opcode -> attribute handle.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the definitions in the Core spec

image image

I'd argue that "Invalid PDU" matches this case the best. I think the latter works better if you are doing a write request with invalid length

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed BT_ATT_ERR_INVALID_ATTRIBUTE_LEN to BT_ATT_ERR_INVALID_PDU.

@lylezhu2012 lylezhu2012 force-pushed the Fix_gatt_coverity_issue branch 2 times, most recently from 32ac770 to 419a543 Compare August 25, 2025 10:40
Comment on lines 1997 to 2001
* operation, so this can fail to allocate resources. However, if the received
* data length is invalid, the error @ref BT_ATT_ERR_INVALID_PDU will be
* returned. For all other API errors are reported as if the server returned
* @ref BT_ATT_ERR_UNLIKELY. There is no way to distinguish between this
* condition and a @ref BT_ATT_ERR_UNLIKELY response from the server itself.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Putting the new documentation here in between the sentences is not right, since this change has nothing to do with the callback returning BT_GATT_ITER_CONTINUE. Let's separate it out to its own paragraph to maintain clarity.

We might also instead put the documentation on bt_gatt_read_func_t.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

In function `parse_read_by_uuid()`, the response length is not checked
before parsing the response PDU. There is a potential issue that the
`len` will be underflowed if the `len` is less than the size of
`struct bt_att_data`.

Check the length before parsing the response PDU. If the length is less
then the size of `struct bt_att_data`, notify the upper layer with the
error `BT_ATT_ERR_INVALID_PDU` and stop the parsing.

Signed-off-by: Lyle Zhu <[email protected]>
@lylezhu2012 lylezhu2012 force-pushed the Fix_gatt_coverity_issue branch from 419a543 to 14c8460 Compare August 27, 2025 01:59
Copy link

Comment on lines +2011 to +2012
* If the received data length is invalid, the callback @p params->func will
* called with the error @ref BT_ATT_ERR_INVALID_PDU.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally I'd only put this in one place. Having the text duplicated in 2 places makes it harder to maintain. I'd perhaps just keep it in bt_gatt_read_func_t

@kartben kartben merged commit 5245307 into zephyrproject-rtos:main Aug 27, 2025
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Bluetooth Host Bluetooth Host (excluding BR/EDR) area: Bluetooth
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants