From 693a830f3e36b8add4b1b9b2a23f65cf73788f73 Mon Sep 17 00:00:00 2001 From: hejiaxin Date: Thu, 27 Aug 2026 15:10:05 +0800 Subject: [PATCH] fix(bt_hid): size HID TX buffers to report length --- .../bt/host/bluedroid/stack/hid/hidd_conn.c | 23 +++++++++++++++---- .../bt/host/bluedroid/stack/hid/hidh_conn.c | 6 +++-- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/components/bt/host/bluedroid/stack/hid/hidd_conn.c b/components/bt/host/bluedroid/stack/hid/hidd_conn.c index 2d4f878ddf9..8b9eca378f6 100644 --- a/components/bt/host/bluedroid/stack/hid/hidd_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidd_conn.c @@ -729,7 +729,8 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param BT_HDR *p_buf; uint8_t *p_out; uint16_t cid; - uint16_t buf_size; + uint16_t max_buf_size; + uint32_t payload_size, buf_size; HIDD_TRACE_VERBOSE("%s: channel(%d), msg_type(%d), len(%d)", __func__, channel, msg_type, len); @@ -742,20 +743,34 @@ tHID_STATUS hidd_conn_send_data(uint8_t channel, uint8_t msg_type, uint8_t param case HID_TRANS_HANDSHAKE: case HID_TRANS_CONTROL: cid = p_hcon->ctrl_cid; - buf_size = HID_CONTROL_BUF_SIZE; + max_buf_size = HID_CONTROL_BUF_SIZE; break; case HID_TRANS_DATA: if (channel == HID_CHANNEL_CTRL) { cid = p_hcon->ctrl_cid; - buf_size = HID_CONTROL_BUF_SIZE; + max_buf_size = HID_CONTROL_BUF_SIZE; } else { cid = p_hcon->intr_cid; - buf_size = HID_INTERRUPT_BUF_SIZE; + max_buf_size = HID_INTERRUPT_BUF_SIZE; } break; default: return (HID_ERR_INVALID_PARAM); } + + /* HID header byte, plus an optional report id byte */ + payload_size = (uint32_t)len + 2; + buf_size = BT_HDR_SIZE + L2CAP_MIN_OFFSET + payload_size; + if (buf_size > max_buf_size) { + HIDD_TRACE_ERROR("hidd tx: len(%d) too large",len); + return (HID_ERR_INVALID_PARAM); + } + /* rem_mtu_size is only known once the channel has been configured */ + if (p_hcon->rem_mtu_size && payload_size > p_hcon->rem_mtu_size) { + HIDD_TRACE_ERROR("hidd tx: len(%d) exceeds peer mtu(%d)",len, p_hcon->rem_mtu_size); + return (HID_ERR_INVALID_PARAM); + } + p_buf = (BT_HDR *)osi_malloc(buf_size); if (p_buf == NULL) return (HID_ERR_NO_RESOURCES); diff --git a/components/bt/host/bluedroid/stack/hid/hidh_conn.c b/components/bt/host/bluedroid/stack/hid/hidh_conn.c index 57697c9b9d4..e24861fc8fe 100644 --- a/components/bt/host/bluedroid/stack/hid/hidh_conn.c +++ b/components/bt/host/bluedroid/stack/hid/hidh_conn.c @@ -865,11 +865,9 @@ tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param, case HID_TRANS_GET_IDLE: case HID_TRANS_SET_IDLE: cid = p_hcon->ctrl_cid; - buf_size = HID_CONTROL_BUF_SIZE; break; case HID_TRANS_DATA: cid = p_hcon->intr_cid; - buf_size = HID_INTERRUPT_BUF_SIZE; break; default: rc = HID_ERR_INVALID_PARAM; @@ -884,6 +882,8 @@ tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param, do { if ( buf == NULL || blank_datc ) { + /* HID header byte, an optional report id byte and the inlined data bytes */ + buf_size = BT_HDR_SIZE + L2CAP_MIN_OFFSET + 2 + use_data; if ((p_buf = (BT_HDR *)osi_malloc(buf_size)) == NULL) { rc = HID_ERR_NO_RESOURCES; goto error; @@ -895,6 +895,8 @@ tHID_STATUS hidh_conn_snd_data (UINT8 dhandle, UINT8 trans_type, UINT8 param, bytes_copied = 0; blank_datc = FALSE; } else if ( (buf->len > (p_hcon->rem_mtu_size - 1))) { + /* HID header byte plus a full (rem_mtu_size - 1) payload segment */ + buf_size = BT_HDR_SIZE + L2CAP_MIN_OFFSET + p_hcon->rem_mtu_size + use_data; if ((p_buf = (BT_HDR *)osi_malloc(buf_size)) == NULL) { rc = HID_ERR_NO_RESOURCES; goto error;