From 569854b55af3d032dc1be1f0c7d0ce2f8fd2d09d Mon Sep 17 00:00:00 2001 From: Zhang Hai Peng Date: Wed, 3 Dec 2025 11:54:22 +0800 Subject: [PATCH] fix(ble/bluedroid): Add length check in prepare write response (cherry picked from commit b03ff3cf218c3974b798a700cf1ede95641fe7af) Co-authored-by: zhanghaipeng --- .../bt/host/bluedroid/stack/gatt/gatt_cl.c | 12 +++++----- .../bluedroid/stack/smp/include/smp_int.h | 5 ++++- .../bt/host/bluedroid/stack/smp/smp_l2c.c | 22 ++++++++++++++++--- .../bt/host/bluedroid/stack/smp/smp_utils.c | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c index 12168dc00d..ddd089f4e0 100644 --- a/components/bt/host/bluedroid/stack/gatt/gatt_cl.c +++ b/components/bt/host/bluedroid/stack/gatt/gatt_cl.c @@ -66,7 +66,7 @@ static const UINT16 disc_type_to_uuid[GATT_DISC_MAX] = { 0 /* no type filtering for DISC_CHAR_DSCPT */ }; -// Use for GATTC discover infomation print +// Use for GATTC discover information print #define GATT_DISC_INFO(fmt, args...) {if (gatt_cb.auto_disc == FALSE) BT_PRINT_I("BT_GATT", fmt, ## args);} /******************************************************************************* @@ -604,7 +604,7 @@ void gatt_process_prep_write_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op GATT_TRACE_DEBUG("value resp op_code = %s len = %d", gatt_dbg_op_name(op_code), len); - if (len < GATT_PREP_WRITE_RSP_MIN_LEN) { + if ((len < GATT_PREP_WRITE_RSP_MIN_LEN) || ((len - 4) > GATT_MAX_ATTR_LEN)) { GATT_TRACE_ERROR("illegal prepare write response length, discard"); gatt_end_operation(p_clcb, GATT_INVALID_PDU, &value); return; @@ -701,7 +701,7 @@ void gatt_process_notification(tGATT_TCB *p_tcb, UINT8 op_code, } p_tcb->ind_count = 0; - /* should notify all registered client with the handle value notificaion/indication + /* should notify all registered client with the handle value notification/indication Note: need to do the indication count and start timer first then do callback */ for (i = 0, p_reg = gatt_cb.cl_rcb; i < GATT_MAX_APPS; i++, p_reg++) { @@ -800,7 +800,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 handle_len = 4; } - value_len -= handle_len; /* substract the handle pairs bytes */ + value_len -= handle_len; /* subtract the handle pairs bytes */ len -= 1; while (len >= (handle_len + value_len)) { @@ -887,7 +887,7 @@ void gatt_process_read_by_type_rsp (tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 gatt_end_operation(p_clcb, GATT_SUCCESS, (void *)p); } return; - } else { /* discover characterisitic */ + } else { /* discover characteristic */ STREAM_TO_UINT8 (record_value.dclr_value.char_prop, p); STREAM_TO_UINT16(record_value.dclr_value.val_handle, p); if (!GATT_HANDLE_IS_VALID(record_value.dclr_value.val_handle)) { @@ -979,7 +979,7 @@ void gatt_process_read_rsp(tGATT_TCB *p_tcb, tGATT_CLCB *p_clcb, UINT8 op_code, if (len == (p_tcb->payload_size - 1) && /* full packet for read or read blob rsp */ len + offset < GATT_MAX_ATTR_LEN) { - GATT_TRACE_DEBUG("full pkt issue read blob for remianing bytes old offset=%d len=%d new offset=%d", + GATT_TRACE_DEBUG("full pkt issue read blob for remaining bytes old offset=%d len=%d new offset=%d", offset, len, p_clcb->counter); gatt_act_read(p_clcb, p_clcb->counter); } else { /* end of request, send callback */ diff --git a/components/bt/host/bluedroid/stack/smp/include/smp_int.h b/components/bt/host/bluedroid/stack/smp/include/smp_int.h index f3ab7ad445..ca2dbfaf07 100644 --- a/components/bt/host/bluedroid/stack/smp/include/smp_int.h +++ b/components/bt/host/bluedroid/stack/smp/include/smp_int.h @@ -197,7 +197,7 @@ enum { }; typedef UINT8 tSMP_BR_STATE; -/* random and encrption activity state */ +/* random and encryption activity state */ enum { SMP_GEN_COMPARE = 1, SMP_GEN_CONFIRM, @@ -363,6 +363,9 @@ extern tSMP_CB *smp_cb_ptr; /* Functions provided by att_main.c */ extern void smp_init (void); +/* SMP command sizes per spec - defined in smp_utils.c */ +extern const UINT8 smp_cmd_size_per_spec[]; + /* smp main */ extern void smp_sm_event(tSMP_CB *p_cb, tSMP_EVENT event, void *p_data); diff --git a/components/bt/host/bluedroid/stack/smp/smp_l2c.c b/components/bt/host/bluedroid/stack/smp/smp_l2c.c index a6f0670598..1f3db502e2 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_l2c.c +++ b/components/bt/host/bluedroid/stack/smp/smp_l2c.c @@ -156,15 +156,31 @@ static void smp_connect_callback (UINT16 channel, BD_ADDR bd_addr, BOOLEAN conne static void smp_data_received(UINT16 channel, BD_ADDR bd_addr, BT_HDR *p_buf) { tSMP_CB *p_cb = &smp_cb; - UINT8 *p = (UINT8 *)(p_buf + 1) + p_buf->offset; - UINT8 cmd ; + UINT8 *p; + UINT8 cmd; SMP_TRACE_EVENT ("\nSMDBG l2c %s\n", __FUNCTION__); + /* Validate packet length before accessing data to prevent out-of-bounds read */ + if (p_buf->len < 1) { + SMP_TRACE_WARNING ("Ignore empty SMP packet (len=%d)\n", p_buf->len); + osi_free (p_buf); + return; + } + + p = (UINT8 *)(p_buf + 1) + p_buf->offset; STREAM_TO_UINT8(cmd, p); /* sanity check */ if ((SMP_OPCODE_MAX < cmd) || (SMP_OPCODE_MIN > cmd)) { - SMP_TRACE_WARNING( "Ignore received command with RESERVED code 0x%02x\n", cmd); + SMP_TRACE_WARNING ("Ignore received command with RESERVED code 0x%02x\n", cmd); + osi_free (p_buf); + return; + } + + /* Validate command length to prevent out-of-bounds read in handler functions */ + if (p_buf->len != smp_cmd_size_per_spec[cmd]) { + SMP_TRACE_WARNING ("Ignore SMP cmd 0x%02x with invalid length %d (expected %d)\n", + cmd, p_buf->len, smp_cmd_size_per_spec[cmd]); osi_free (p_buf); return; } diff --git a/components/bt/host/bluedroid/stack/smp/smp_utils.c b/components/bt/host/bluedroid/stack/smp/smp_utils.c index 48ba6c0ae3..8ec4d548ac 100644 --- a/components/bt/host/bluedroid/stack/smp/smp_utils.c +++ b/components/bt/host/bluedroid/stack/smp/smp_utils.c @@ -55,7 +55,7 @@ #define SMP_PAIR_KEYPR_NOTIF_SIZE (1 /* opcode */ + 1 /*Notif Type*/) /* SMP command sizes per spec */ -static const UINT8 smp_cmd_size_per_spec[] = { +const UINT8 smp_cmd_size_per_spec[] = { 0, SMP_PAIRING_REQ_SIZE, /* 0x01: pairing request */ SMP_PAIRING_REQ_SIZE, /* 0x02: pairing response */