From 97905afccc3741266402e70aef1fc7227b8382e1 Mon Sep 17 00:00:00 2001 From: zhanghaipeng Date: Mon, 15 Jun 2026 15:27:32 +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. --- 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 76432c4f1b6..e4d27234bd1 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,