From 7b2b31bb0d6a909bfdb332345c3d649053a20a0f Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Fri, 26 Jun 2026 20:24:16 +0800 Subject: [PATCH] fix(ble/bluedroid): cap Read By Type response length at ATT maximum Read By Type Response Length is one octet (max 255). When MTU was large enough to return a long characteristic value in one pair, the server wrote (UINT8)(value_len + 2) and overflowed (e.g. 513 -> 1), so the client rejected the PDU as GATT_INVALID_PDU (0x04). Cap server value to 253 bytes per pair, clamp the length byte, and continue long reads via Read Blob when the capped size is returned. (cherry picked from commit 97905afccc3741266402e70aef1fc7227b8382e1) Co-authored-by: zhanghaipeng --- components/bt/host/bluedroid/stack/gatt/gatt_cl.c | 6 +++++- components/bt/host/bluedroid/stack/gatt/gatt_db.c | 8 +++++++- .../bt/host/bluedroid/stack/gatt/include/gatt_int.h | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c index 28a50c4ac35..1fc86945659 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c @@ -891,7 +891,11 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 /* value_len is the length of current record's value; use it to avoid overread when multiple records present */ p_clcb->counter = value_len; p_clcb->s_handle = handle; - if ( p_clcb->counter == (p_clcb->p_tcb->payload_size - 4)) { + UINT16 max_rbtype_val_len = (p_clcb->p_tcb->payload_size - 4); + if (max_rbtype_val_len > GATT_MAX_READ_BY_TYPE_VALUE_LEN) { + max_rbtype_val_len = GATT_MAX_READ_BY_TYPE_VALUE_LEN; + } + if (p_clcb->counter == max_rbtype_val_len) { p_clcb->op_subtype = GATT_READ_BY_HANDLE; if (!p_clcb->p_attr_buf) { p_clcb->p_attr_buf = (UINT8 *)osi_malloc(GATT_MAX_ATTR_LEN); diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_db.c b/components/bt/host/bluedroid/stack/gatt/gatt_db.c index 73037155f27..299eb80927d 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_db.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_db.c @@ -370,7 +370,13 @@ tGATT_STATUS gatts_db_read_attr_value_by_type (tGATT_TCB *p_tcb, UINT16_TO_STREAM (p, p_attr->handle); - status = read_attr_value ((void *)p_attr, 0, &p, FALSE, (UINT16)(*p_len - 2), &len, sec_flag, key_size); + { + UINT16 max_val_len = (UINT16)(*p_len - 2); + if (max_val_len > GATT_MAX_READ_BY_TYPE_VALUE_LEN) { + max_val_len = GATT_MAX_READ_BY_TYPE_VALUE_LEN; + } + status = read_attr_value ((void *)p_attr, 0, &p, FALSE, max_val_len, &len, sec_flag, key_size); + } if (status == GATT_PENDING) { diff --git a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h index 44af16eec70..0f2a7b08831 100644 --- a/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h +++ b/components/bt/host/bluedroid/stack/gatt/include/gatt_int.h @@ -76,6 +76,10 @@ typedef UINT8 tGATT_SEC_ACTION; #define GATT_HDR_SIZE 3 /* 1B opcode + 2B handle */ +/* ATT Read By Type Response: Length field is 1 octet (max 255). */ +#define GATT_MAX_READ_BY_TYPE_PAIR_LEN 255 +#define GATT_MAX_READ_BY_TYPE_VALUE_LEN (GATT_MAX_READ_BY_TYPE_PAIR_LEN - 2) + /** * Wait for ATT cmd response timeout value (40 seconds). * The max connection supervision timeout is 32 seconds,