From 5aa4edacdbe495fa5b29856f0f670ed123dbc480 Mon Sep 17 00:00:00 2001 From: Linyan Liu Date: Tue, 30 Jun 2026 11:45:14 +0800 Subject: [PATCH 1/2] fix(ble_iso): Fix ISO SDU header pulled without minimum length check --- components/bt/esp_ble_iso/host/iso/iso.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/components/bt/esp_ble_iso/host/iso/iso.c b/components/bt/esp_ble_iso/host/iso/iso.c index 8ecfb5b9ec5..9516cccf2f1 100644 --- a/components/bt/esp_ble_iso/host/iso/iso.c +++ b/components/bt/esp_ble_iso/host/iso/iso.c @@ -624,6 +624,17 @@ void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags) case BT_ISO_SINGLE: iso_info.flags = 0; + /* A malformed ISO packet whose ISO_Data_Load_Length is below the SDU + * header size would underflow buf->len in net_buf_pull_mem (the guard + * assert is compiled out in release) and leak OOB bytes into the recv + * callback. Drop it before pulling the header. + */ + if (buf->len < (ts ? sizeof(struct bt_hci_iso_sdu_ts_hdr) + : sizeof(struct bt_hci_iso_sdu_hdr))) { + LOG_ERR("ShortIsoSduHdr[%u][%u]", buf->len, ts); + return; + } + /* The ISO_Data_Load field contains either the first fragment * of an SDU or a complete SDU. */ From ec4aa2fa75f4b05b21b1e7143a4264b2fb43f502 Mon Sep 17 00:00:00 2001 From: Liu Linyan Date: Wed, 1 Jul 2026 11:59:45 +0800 Subject: [PATCH 2/2] fix(ble_iso): Fix null dereference may happened during BIG/CIG creation --- components/bt/esp_ble_iso/host/iso/iso.c | 67 +++++++++++++++++++----- 1 file changed, 55 insertions(+), 12 deletions(-) diff --git a/components/bt/esp_ble_iso/host/iso/iso.c b/components/bt/esp_ble_iso/host/iso/iso.c index 9516cccf2f1..35e33e0361f 100644 --- a/components/bt/esp_ble_iso/host/iso/iso.c +++ b/components/bt/esp_ble_iso/host/iso/iso.c @@ -1656,10 +1656,27 @@ static bool is_advanced_cig_param(const struct bt_iso_cig_param *param) return true; } + /* This probe runs before valid_cig_param(); guard structure here so + * caller misuse (NULL cis_channels/cis/qos, or an over-reported num_cis) + * falls through to that check's -EINVAL instead of a NULL or + * out-of-bounds deref in this probe. + */ + if (param->cis_channels == NULL || + param->num_cis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_cis > CONFIG_BT_ISO_MAX_CHAN) { + return false; + } + /* Check if any of the CIS contain any test-param-only values */ for (uint8_t i = 0U; i < param->num_cis; i++) { const struct bt_iso_chan *cis = param->cis_channels[i]; - const struct bt_iso_chan_qos *qos = cis->qos; + const struct bt_iso_chan_qos *qos; + + if (cis == NULL || cis->qos == NULL) { + continue; + } + + qos = cis->qos; if (qos->num_subevents > 0U) { return true; @@ -1785,6 +1802,14 @@ static bool valid_cig_param(const struct bt_iso_cig_param *param, bool advanced, return false; } + /* Not guaranteed by all callers (bt_iso_cig_reconfigure does not pre-check + * it); the per-CIS loop below dereferences cis_channels[i] directly. + */ + if (param->cis_channels == NULL) { + LOG_ERR("CisChansNull"); + return false; + } + if (param->num_cis > BT_ISO_MAX_GROUP_ISO_COUNT || param->num_cis > CONFIG_BT_ISO_MAX_CHAN) { LOG_ERR("TooLargeNumCis[%u][%u]", @@ -2659,17 +2684,32 @@ static bool is_advanced_big_param(const struct bt_iso_big_create_param *param) return true; } + /* This probe runs before valid_big_param(); guard structure here so + * caller misuse (NULL bis_channels/bis/qos/qos->tx, or an over-reported + * num_bis) falls through to that check's -EINVAL instead of a NULL or + * out-of-bounds deref in this probe. + */ + if (param->bis_channels == NULL || + param->num_bis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_bis > CONFIG_BT_ISO_MAX_CHAN) { + return false; + } + /* Check if any of the CIS contain any test-param-only values */ for (uint8_t i = 0U; i < param->num_bis; i++) { const struct bt_iso_chan *bis = param->bis_channels[i]; - const struct bt_iso_chan_qos *qos = bis->qos; + const struct bt_iso_chan_qos *qos; + + if (bis == NULL || bis->qos == NULL || bis->qos->tx == NULL) { + continue; + } + + qos = bis->qos; if (qos->num_subevents > 0U) { return true; } - assert(qos->tx != NULL && "BigWithNullTx"); - if (qos->tx->max_pdu > 0U || qos->tx->burst_number > 0U) { return true; } @@ -2693,6 +2733,17 @@ static bool valid_big_param(const struct bt_iso_big_create_param *param, bool ad return false; } + /* Bound num_bis before the per-BIS loop so a caller that over-reports it + * cannot drive the loop past the bis_channels[] array. + */ + CHECKIF(param->num_bis > BT_ISO_MAX_GROUP_ISO_COUNT || + param->num_bis > CONFIG_BT_ISO_MAX_CHAN) { + LOG_ERR("TooLargeNumBis[%u][%u][%u]", + param->num_bis, BT_ISO_MAX_GROUP_ISO_COUNT, CONFIG_BT_ISO_MAX_CHAN); + + return false; + } + for (uint8_t i = 0; i < param->num_bis; i++) { struct bt_iso_chan *bis = param->bis_channels[i]; @@ -2736,14 +2787,6 @@ static bool valid_big_param(const struct bt_iso_big_create_param *param, bool ad return false; } - CHECKIF(param->num_bis > BT_ISO_MAX_GROUP_ISO_COUNT || - param->num_bis > CONFIG_BT_ISO_MAX_CHAN) { - LOG_ERR("TooLargeNumBis[%u][%u]", - param->num_bis, MAX(CONFIG_BT_ISO_MAX_CHAN, BT_ISO_MAX_GROUP_ISO_COUNT)); - - return false; - } - CHECKIF(!IN_RANGE(param->interval, BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX)) { LOG_ERR("InvInterval[%u]", param->interval);