This is an automated email from the ASF dual-hosted git repository.

sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 412e21f0f716a7b4a27569ffb1502714fac21ffd
Author: Szymon Janc <[email protected]>
AuthorDate: Wed Oct 7 18:08:31 2026 +0200

    nimble/ll: Validate HCI ISO data packet boundary flags
    
    HCI ISO data packet fragmentation was validated only with asserts.
    Without asserts enabled, continuation or last fragment received without
    first fragment resulted in NULL pointer dereference and first or
    complete fragment received while SDU was pending leaked buffers. Handle
    such cases at runtime, validate header length before reading it and
    free pending fragment when ISO connection is freed.
    
    Assisted-by: Claude:claude-opus-5-5
---
 nimble/controller/src/ble_ll_iso.c | 37 +++++++++++++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 4 deletions(-)

diff --git a/nimble/controller/src/ble_ll_iso.c 
b/nimble/controller/src/ble_ll_iso.c
index 03a31d5fa..55b4dd6d9 100644
--- a/nimble/controller/src/ble_ll_iso.c
+++ b/nimble/controller/src/ble_ll_iso.c
@@ -240,6 +240,11 @@ ble_ll_iso_data_in(struct os_mbuf *om)
     uint16_t ts_flag;
     uint32_t timestamp = 0;
 
+    if (om->om_len < sizeof(*hci_iso)) {
+        os_mbuf_free_chain(om);
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
     hci_iso = (void *)om->om_data;
 
     handle = le16toh(hci_iso->handle);
@@ -257,6 +262,12 @@ ble_ll_iso_data_in(struct os_mbuf *om)
     data_hdr_len = 0;
     if ((pb_flag == BLE_HCI_ISO_PB_FIRST) ||
         (pb_flag == BLE_HCI_ISO_PB_COMPLETE)) {
+        if (om->om_len < sizeof(*hci_iso) + sizeof(*hci_iso_data) +
+                             (ts_flag ? sizeof(uint32_t) : 0)) {
+            os_mbuf_free_chain(om);
+            return BLE_ERR_INV_HCI_CMD_PARMS;
+        }
+
         blehdr = BLE_MBUF_HDR_PTR(om);
         blehdr->txiso.packet_seq_num = ++conn->mux.sdu_counter;
         blehdr->txiso.cpu_timestamp = ble_ll_tmr_get();
@@ -279,20 +290,33 @@ ble_ll_iso_data_in(struct os_mbuf *om)
 
     switch (pb_flag) {
     case BLE_HCI_ISO_PB_FIRST:
-        BLE_LL_ASSERT(!conn->frag);
+        /* Drop incomplete SDU, if any */
+        if (conn->frag) {
+            os_mbuf_free_chain(conn->frag);
+        }
         conn->frag = om;
         om = NULL;
         break;
     case BLE_HCI_ISO_PB_CONTINUATION:
-        BLE_LL_ASSERT(conn->frag);
+        if (!conn->frag) {
+            os_mbuf_free_chain(om);
+            return BLE_ERR_INV_HCI_CMD_PARMS;
+        }
         os_mbuf_concat(conn->frag, om);
         om = NULL;
         break;
     case BLE_HCI_ISO_PB_COMPLETE:
-        BLE_LL_ASSERT(!conn->frag);
+        /* Drop incomplete SDU, if any */
+        if (conn->frag) {
+            os_mbuf_free_chain(conn->frag);
+            conn->frag = NULL;
+        }
         break;
     case BLE_HCI_ISO_PB_LAST:
-        BLE_LL_ASSERT(conn->frag);
+        if (!conn->frag) {
+            os_mbuf_free_chain(om);
+            return BLE_ERR_INV_HCI_CMD_PARMS;
+        }
         os_mbuf_concat(conn->frag, om);
         om = conn->frag;
         conn->frag = NULL;
@@ -411,6 +435,11 @@ ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn)
     STAILQ_REMOVE(&ll_iso_conn_q, conn, ble_ll_iso_conn, iso_conn_q_next);
     OS_EXIT_CRITICAL(sr);
 
+    if (conn->frag) {
+        os_mbuf_free_chain(conn->frag);
+        conn->frag = NULL;
+    }
+
     ble_ll_isoal_mux_free(&conn->mux);
 }
 

Reply via email to