* [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues
@ 2026-09-18 3:27 Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
` (6 more replies)
0 siblings, 7 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-18 3:27 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Mohammad Shuab Siddique
From: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
This series fixes five independent out-of-bounds issues in flow,
Rx-datapath and naming code in the bnxt PMD:
- two stack-allocated variable-length arrays in flow-stats sizing
that risked stack exhaustion,
- a TPA aggregation ID read from a completion and used to index
rxr->tpa_info[] without a bounds check,
- three separate sprintf() calls into fixed-size buffers with no
bound on the formatted string length, plus three related bugs
(a leak, a stale flag, and a lock left held) introduced by this
change's own new early-return paths and fixed here,
- a caller-supplied MAC pool index used before being validated
against bp->max_vnics, and an unbounded flow item/action skip
loop that could walk off the end of the pattern array, and
- a firmware-supplied Rx completion opaque value used unmasked as
an rx_buf_ring[] index, an aggregation-segment count guarded only
by a release-mode-compiled-out RTE_ASSERT, and an unclamped VF
VNIC-count from firmware.
Each patch is independently bisectable and was validated with a
scoped net/bnxt build (and, for split points, an intermediate-commit
build) in addition to the full compliance gate.
Chenna Arnoori (1):
net/bnxt: fix bounds in MAC pool index and flow parsing
Joseph Wong (1):
net/bnxt: fix stack exhaustion in flow stats
Keegan Freyhof (1):
net/bnxt: harden sprintf bounds for device memory names
Kishore Padmanabha (1):
net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds
Mohammad Shuab Siddique (1):
net/bnxt: fix bounds on TPA aggregation ID from completions
drivers/net/bnxt/bnxt.h | 15 +++++++
drivers/net/bnxt/bnxt_ethdev.c | 43 +++++++++++++-------
drivers/net/bnxt/bnxt_flow.c | 28 +++++++++----
drivers/net/bnxt/bnxt_hwrm.c | 74 +++++++++++++++++++++++++---------
drivers/net/bnxt/bnxt_rxr.c | 57 ++++++++++++++++++++------
drivers/net/bnxt/bnxt_stats.c | 18 ++++-----
6 files changed, 173 insertions(+), 62 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/5] net/bnxt: fix stack exhaustion in flow stats
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
@ 2026-09-18 3:27 ` Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions Mohammad Shuab Siddique
` (5 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-18 3:27 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Joseph Wong, stable, Mohammad Shuab Siddique
From: Joseph Wong <joseph.wong@broadcom.com>
In bnxt_flow_stats_cnt(), two variable-length arrays are allocated
on the stack. These arrays are allocated merely to be used to
calculate the dimensions via RTE_DIM(). Replace with the
mathematical equivalent to avoid potential stack exhaustion.
Fixes: 1e2f8aca2cc1 ("net/bnxt: fix allocation of flow stat related structs")
Cc: stable@dpdk.org
Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_stats.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index ba858710a5..c4efcb4b17 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -1095,12 +1095,8 @@ int bnxt_flow_stats_cnt(struct bnxt *bp)
{
if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
- BNXT_FLOW_XSTATS_EN(bp)) {
- struct bnxt_xstats_name_off flow_bytes[bp->max_l2_ctx];
- struct bnxt_xstats_name_off flow_pkts[bp->max_l2_ctx];
-
- return RTE_DIM(flow_bytes) + RTE_DIM(flow_pkts);
- }
+ BNXT_FLOW_XSTATS_EN(bp))
+ return 2 * bp->max_l2_ctx;
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
@ 2026-09-18 3:27 ` Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
` (4 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-18 3:27 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Mohammad Shuab Siddique, stable
From: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
TPA start/end and TPA v2 abuf paths indexed rxr->tpa_info[] using
the aggregation ID from the completion without checking
BNXT_TPA_MAX_AGGS. Add bounds checks and schedule a ring reset on
failure. Also fix abuf aggregation ID decode to use
rte_le_to_cpu_16() when reading the device field.
Fixes: 0958d8b6435 ("net/bnxt: support LRO")
Fixes: b150a7e7ee6 ("net/bnxt: support LRO on Thor adapters")
Cc: stable@dpdk.org
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_rxr.c | 47 ++++++++++++++++++++++++++++---------
1 file changed, 36 insertions(+), 11 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c
index 0fab4ddf78..87640eaa79 100644
--- a/drivers/net/bnxt/bnxt_rxr.c
+++ b/drivers/net/bnxt/bnxt_rxr.c
@@ -236,12 +236,19 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
struct rx_tpa_start_cmpl_hi *tpa_start1)
{
struct bnxt_rx_ring_info *rxr = rxq->rx_ring;
- uint16_t agg_id;
- uint16_t data_cons;
struct bnxt_tpa_info *tpa_info;
+ uint32_t data_cons, agg_id;
+ struct bnxt *bp = rxq->bp;
struct rte_mbuf *mbuf;
- agg_id = bnxt_tpa_start_agg_id(rxq->bp, tpa_start);
+ agg_id = bnxt_tpa_start_agg_id(bp, tpa_start);
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA start: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ return;
+ }
data_cons = tpa_start->opaque;
tpa_info = &rxr->tpa_info[agg_id];
@@ -268,7 +275,7 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
mbuf->port = rxq->port_id;
mbuf->ol_flags = RTE_MBUF_F_RX_LRO;
- bnxt_tpa_get_metadata(rxq->bp, tpa_info, tpa_start, tpa_start1);
+ bnxt_tpa_get_metadata(bp, tpa_info, tpa_start, tpa_start1);
if (likely(tpa_info->hash_valid)) {
mbuf->hash.rss = tpa_info->rss_hash;
@@ -278,7 +285,7 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
mbuf->ol_flags |= RTE_MBUF_F_RX_FDIR | RTE_MBUF_F_RX_FDIR_ID;
}
- if (tpa_info->vlan_valid && BNXT_RX_VLAN_STRIP_EN(rxq->bp)) {
+ if (tpa_info->vlan_valid && BNXT_RX_VLAN_STRIP_EN(bp)) {
mbuf->vlan_tci = tpa_info->vlan;
mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
}
@@ -421,20 +428,21 @@ static inline struct rte_mbuf *bnxt_tpa_end(
{
struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
struct bnxt_rx_ring_info *rxr = rxq->rx_ring;
- uint16_t agg_id;
+ struct bnxt_tpa_info *tpa_info;
+ struct bnxt *bp = rxq->bp;
+ uint8_t payload_offset;
struct rte_mbuf *mbuf;
uint8_t agg_bufs;
- uint8_t payload_offset;
- struct bnxt_tpa_info *tpa_info;
+ uint32_t agg_id;
if (unlikely(rxq->in_reset)) {
PMD_DRV_LOG_LINE(ERR, "rxq->in_reset: raw_cp_cons:%d",
*raw_cp_cons);
- bnxt_discard_rx(rxq->bp, cpr, raw_cp_cons, tpa_end);
+ bnxt_discard_rx(bp, cpr, raw_cp_cons, tpa_end);
return NULL;
}
- if (BNXT_CHIP_P5_P7(rxq->bp)) {
+ if (BNXT_CHIP_P5_P7(bp)) {
struct rx_tpa_v2_end_cmpl *th_tpa_end;
struct rx_tpa_v2_end_cmpl_hi *th_tpa_end1;
@@ -451,6 +459,14 @@ static inline struct rte_mbuf *bnxt_tpa_end(
payload_offset = tpa_end->payload_offset;
}
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA end: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ return NULL;
+ }
+
tpa_info = &rxr->tpa_info[agg_id];
mbuf = tpa_info->mbuf;
RTE_ASSERT(mbuf != NULL);
@@ -1135,9 +1151,18 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt,
if (cmp_type == RX_TPA_V2_ABUF_CMPL_TYPE_RX_TPA_AGG) {
struct rx_tpa_v2_abuf_cmpl *rx_agg = (void *)rxcmp;
- uint16_t agg_id = rte_cpu_to_le_16(rx_agg->agg_id);
+ uint32_t agg_id = rte_le_to_cpu_16(rx_agg->agg_id);
struct bnxt_tpa_info *tpa_info;
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA abuf: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ rc = -EINVAL;
+ goto next_rx;
+ }
+
tpa_info = &rxr->tpa_info[agg_id];
RTE_ASSERT(tpa_info->agg_count < 16);
tpa_info->agg_arr[tpa_info->agg_count++] = *rx_agg;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/5] net/bnxt: harden sprintf bounds for device memory names
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions Mohammad Shuab Siddique
@ 2026-09-18 3:27 ` Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
` (3 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-18 3:27 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Keegan Freyhof, Mohammad Shuab Siddique
From: Keegan Freyhof <keegan.freyhof@broadcom.com>
sprintf() into fixed-size stack buffers such as
char type[RTE_MEMZONE_NAMESIZE] does not bound the write to the
buffer, so a long enough formatted string (e.g. from PCI address
fields) overflows it.
Add check_snprintf_rc(), a helper that logs and returns an error on a
failed snprintf() call and logs (without failing) a truncated one.
Convert sprintf() calls building a memzone/malloc name to snprintf()
plus this check, and add the same check to the existing snprintf()
calls building HWRM CFA pair_name request fields. Unlike a truncated
memzone/malloc label, a truncated pair_name would be sent to firmware
and could match the wrong pair or none at all, so
bnxt_hwrm_cfa_pair_exists()/_alloc()/_free() additionally reject a
truncated pair_name outright instead of proceeding.
This change introduces and corrects three bugs of its own.
In bnxt_hwrm_ver_get(), free bp->hwrm_short_cmd_req_addr (and null it)
before checking the new snprintf's return, instead of after, so an
early return on a snprintf failure doesn't leak the previous
allocation; also clear BNXT_FLAG_SHORT_CMD on that same early return,
since it may already have been set a few lines above and would
otherwise claim short-command support with no buffer allocated. In
bnxt_hwrm_cfa_pair_exists()/_alloc()/_free(), the new early-return
paths exited without releasing bp->hwrm_lock (held since the
preceding HWRM_PREP()), which would deadlock every later HWRM call;
added the missing HWRM_UNLOCK() before each return.
Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt.h | 15 +++++++
drivers/net/bnxt/bnxt_ethdev.c | 24 ++++++++----
drivers/net/bnxt/bnxt_hwrm.c | 71 +++++++++++++++++++++++++---------
drivers/net/bnxt/bnxt_stats.c | 10 +++--
4 files changed, 92 insertions(+), 28 deletions(-)
diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h
index 336de75da0..bfd6cf15b7 100644
--- a/drivers/net/bnxt/bnxt.h
+++ b/drivers/net/bnxt/bnxt.h
@@ -1285,6 +1285,21 @@ extern int bnxt_logtype_driver;
BNXT_LINK_SPEEDS_V2_VF((bp))))
#define BNXT_MAX_SPEED_LANES 8
#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_P5_P7(bp) || (bp)->max_tpa_v2)
+
+static inline int
+check_snprintf_rc(int rc, size_t max_size, const char *ctx)
+{
+ if (rc < 0) {
+ PMD_DRV_LOG_LINE(ERR, "Error when creating string for %s", ctx);
+ return rc;
+ }
+
+ if (rc >= (int)max_size)
+ PMD_DRV_LOG_LINE(INFO, "String truncated when creating string for %s", ctx);
+
+ return 0;
+}
+
extern const struct rte_flow_ops bnxt_ulp_rte_flow_ops;
int32_t bnxt_ulp_port_init(struct bnxt *bp);
void bnxt_ulp_port_deinit(struct bnxt *bp);
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 8e8ead8f61..27cf67c04f 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -647,13 +647,15 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
{
struct rte_pci_device *pdev = bp->pdev;
char type[RTE_MEMZONE_NAMESIZE];
+ int rc = 0, snp_rc = 0;
uint16_t max_fc;
- int rc = 0;
max_fc = bp->flow_stat->max_fc;
- sprintf(type, "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_rx_fc_in_") < 0)
+ return snp_rc;
/* 4 bytes for each counter-id */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 4,
@@ -661,8 +663,10 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_rx_fc_out_") < 0)
+ return snp_rc;
/* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 16,
@@ -670,8 +674,10 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_tx_fc_in_") < 0)
+ return snp_rc;
/* 4 bytes for each counter-id */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 4,
@@ -679,8 +685,10 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_tx_fc_out_") < 0)
+ return snp_rc;
/* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 16,
@@ -5226,8 +5234,8 @@ int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp)
{
struct bnxt_ctx_mem_info *ctx = bp->ctx;
struct bnxt_ctx_mem *ctx2;
+ int rc = 0, snp_rc = 0;
uint16_t type;
- int rc = 0;
ctx2 = &ctx->ctx_arr[0];
for (type = 0; type < ctx->types && rc == 0; type++) {
@@ -5248,7 +5256,9 @@ int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp)
for (i = 0; i < w && rc == 0; i++) {
char name[RTE_MEMZONE_NAMESIZE] = {0};
- sprintf(name, "_%d_%d", i, type);
+ snp_rc = snprintf(name, sizeof(name), "_%d_%d", i, type);
+ if (check_snprintf_rc(snp_rc, sizeof(name), "index and type.") < 0)
+ return snp_rc;
if (ctxm->entry_multiple)
entries = bnxt_roundup(ctxm->max_entries,
diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 1615b36aae..0143da8789 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -1583,12 +1583,12 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp)
int bnxt_hwrm_ver_get(struct bnxt *bp, uint32_t timeout)
{
- int rc = 0;
struct hwrm_ver_get_input req = {.req_type = 0 };
struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr;
uint32_t fw_version;
uint16_t max_resp_len;
char type[RTE_MEMZONE_NAMESIZE];
+ int rc = 0, snp_rc = 0;
uint32_t dev_caps_cfg;
bp->max_req_len = HWRM_MAX_REQ_LEN;
@@ -1669,11 +1669,15 @@ int bnxt_hwrm_ver_get(struct bnxt *bp, uint32_t timeout)
(dev_caps_cfg &
HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED)) ||
bp->hwrm_max_ext_req_len > HWRM_MAX_REQ_LEN) {
- sprintf(type, "bnxt_hwrm_short_" PCI_PRI_FMT,
- bp->pdev->addr.domain, bp->pdev->addr.bus,
- bp->pdev->addr.devid, bp->pdev->addr.function);
-
+ snp_rc = snprintf(type, sizeof(type), "bnxt_hwrm_short_" PCI_PRI_FMT,
+ bp->pdev->addr.domain, bp->pdev->addr.bus,
+ bp->pdev->addr.devid, bp->pdev->addr.function);
rte_free(bp->hwrm_short_cmd_req_addr);
+ bp->hwrm_short_cmd_req_addr = NULL;
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_hwrm_short_") < 0) {
+ bp->flags &= ~BNXT_FLAG_SHORT_CMD;
+ return snp_rc;
+ }
bp->hwrm_short_cmd_req_addr =
rte_malloc(type, bp->hwrm_max_ext_req_len, 0);
@@ -3541,9 +3545,12 @@ int bnxt_alloc_hwrm_resources(struct bnxt *bp)
{
struct rte_pci_device *pdev = bp->pdev;
char type[RTE_MEMZONE_NAMESIZE];
+ int snp_rc = 0;
- sprintf(type, "bnxt_hwrm_" PCI_PRI_FMT, pdev->addr.domain,
- pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ snp_rc = snprintf(type, sizeof(type), "bnxt_hwrm_" PCI_PRI_FMT, pdev->addr.domain,
+ pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_hwrm_") < 0)
+ return snp_rc;
bp->max_resp_len = BNXT_PAGE_SIZE;
bp->hwrm_cmd_resp_addr = rte_malloc(type, bp->max_resp_len, 0);
if (bp->hwrm_cmd_resp_addr == NULL)
@@ -6780,6 +6787,7 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp)
{
struct bnxt_ctx_mem_info *ctx = bp->ctx;
char name[RTE_MEMZONE_NAMESIZE];
+ int snp_rc = 0;
uint16_t type;
for (type = 0; type < ctx->types; type++) {
@@ -6792,8 +6800,10 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp)
if (ctxm->instance_bmap)
n = hweight32(ctxm->instance_bmap);
- sprintf(name, "bnxt_ctx_pgmem_%d_%d",
- bp->eth_dev->data->port_id, type);
+ snp_rc = snprintf(name, sizeof(name), "bnxt_ctx_pgmem_%d_%d",
+ bp->eth_dev->data->port_id, type);
+ if (check_snprintf_rc(snp_rc, sizeof(name), "bnxt_ctx_pgmem_") < 0)
+ return snp_rc;
ctxm->pg_info = rte_malloc(name, sizeof(*ctxm->pg_info) * n,
RTE_CACHE_LINE_SIZE);
if (!ctxm->pg_info)
@@ -7751,7 +7761,7 @@ int bnxt_hwrm_cfa_pair_exists(struct bnxt *bp, struct bnxt_representor *rep_bp)
{
struct hwrm_cfa_pair_info_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_cfa_pair_info_input req = {0};
- int rc = 0;
+ int rc = 0, snp_rc = 0;
if (!(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp))) {
PMD_DRV_LOG_LINE(DEBUG,
@@ -7760,8 +7770,16 @@ int bnxt_hwrm_cfa_pair_exists(struct bnxt *bp, struct bnxt_representor *rep_bp)
}
HWRM_PREP(&req, HWRM_CFA_PAIR_INFO, BNXT_USE_CHIMP_MB);
- snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
- bp->eth_dev->data->name, rep_bp->vf_id);
+ snp_rc = snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
+ bp->eth_dev->data->name, rep_bp->vf_id);
+ if (check_snprintf_rc(snp_rc, sizeof(req.pair_name), "svfr") < 0) {
+ HWRM_UNLOCK();
+ return snp_rc;
+ }
+ if (snp_rc >= (int)sizeof(req.pair_name)) {
+ HWRM_UNLOCK();
+ return -EINVAL;
+ }
req.flags =
rte_cpu_to_le_32(HWRM_CFA_PAIR_INFO_INPUT_FLAGS_LOOKUP_TYPE);
@@ -7779,7 +7797,7 @@ int bnxt_hwrm_cfa_pair_alloc(struct bnxt *bp, struct bnxt_representor *rep_bp)
{
struct hwrm_cfa_pair_alloc_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_cfa_pair_alloc_input req = {0};
- int rc;
+ int rc, snp_rc = 0;
if (!(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp))) {
PMD_DRV_LOG_LINE(DEBUG,
@@ -7789,8 +7807,16 @@ int bnxt_hwrm_cfa_pair_alloc(struct bnxt *bp, struct bnxt_representor *rep_bp)
HWRM_PREP(&req, HWRM_CFA_PAIR_ALLOC, BNXT_USE_CHIMP_MB);
req.pair_mode = HWRM_CFA_PAIR_FREE_INPUT_PAIR_MODE_REP2FN_TRUFLOW;
- snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
- bp->eth_dev->data->name, rep_bp->vf_id);
+ snp_rc = snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
+ bp->eth_dev->data->name, rep_bp->vf_id);
+ if (check_snprintf_rc(snp_rc, sizeof(req.pair_name), "svfr") < 0) {
+ HWRM_UNLOCK();
+ return snp_rc;
+ }
+ if (snp_rc >= (int)sizeof(req.pair_name)) {
+ HWRM_UNLOCK();
+ return -EINVAL;
+ }
req.pf_b_id = rep_bp->parent_pf_idx;
req.vf_b_id = BNXT_REP_PF(rep_bp) ? rte_cpu_to_le_16(((uint16_t)-1)) :
@@ -7825,7 +7851,7 @@ int bnxt_hwrm_cfa_pair_free(struct bnxt *bp, struct bnxt_representor *rep_bp)
{
struct hwrm_cfa_pair_free_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_cfa_pair_free_input req = {0};
- int rc;
+ int rc, snp_rc = 0;
if (!(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp))) {
PMD_DRV_LOG_LINE(DEBUG,
@@ -7834,8 +7860,17 @@ int bnxt_hwrm_cfa_pair_free(struct bnxt *bp, struct bnxt_representor *rep_bp)
}
HWRM_PREP(&req, HWRM_CFA_PAIR_FREE, BNXT_USE_CHIMP_MB);
- snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
- bp->eth_dev->data->name, rep_bp->vf_id);
+ snp_rc = snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
+ bp->eth_dev->data->name, rep_bp->vf_id);
+ if (check_snprintf_rc(snp_rc, sizeof(req.pair_name), "svfr") < 0) {
+ HWRM_UNLOCK();
+ return snp_rc;
+ }
+ if (snp_rc >= (int)sizeof(req.pair_name)) {
+ HWRM_UNLOCK();
+ return -EINVAL;
+ }
+
req.pf_b_id = rep_bp->parent_pf_idx;
req.pair_mode = HWRM_CFA_PAIR_FREE_INPUT_PAIR_MODE_REP2FN_TRUFLOW;
req.vf_id = BNXT_REP_PF(rep_bp) ? rte_cpu_to_le_16(((uint16_t)-1)) :
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index c4efcb4b17..19153f96ae 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -1108,7 +1108,7 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
unsigned int stat_cnt;
unsigned int i, count = 0, sz;
- int rc;
+ int rc, snp_rc = 0;
rc = is_bnxt_in_error(bp);
if (rc)
@@ -1183,12 +1183,16 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
for (i = 0; i < bp->max_l2_ctx; i++) {
char buf[RTE_ETH_XSTATS_NAME_SIZE];
- sprintf(buf, "flow_%d_bytes", i);
+ snp_rc = snprintf(buf, sizeof(buf), "flow_%d_bytes", i);
+ if (check_snprintf_rc(snp_rc, sizeof(buf), "flow_%d_bytes") < 0)
+ return snp_rc;
strlcpy(xstats_names[count].name, buf,
sizeof(xstats_names[count].name));
count++;
- sprintf(buf, "flow_%d_packets", i);
+ snp_rc = snprintf(buf, sizeof(buf), "flow_%d_packets", i);
+ if (check_snprintf_rc(snp_rc, sizeof(buf), "flow_%d_packets") < 0)
+ return snp_rc;
strlcpy(xstats_names[count].name, buf,
sizeof(xstats_names[count].name));
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (2 preceding siblings ...)
2026-09-18 3:27 ` [PATCH 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
@ 2026-09-18 3:27 ` Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
` (2 subsequent siblings)
6 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-18 3:27 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Chenna Arnoori, stable,
Mohammad Shuab Siddique
From: Chenna Arnoori <chenna.arnoori@broadcom.com>
Two independent out-of-bounds issues in the driver:
- bnxt_mac_addr_add_op() indexed bp->vnic_info[pool] with a
caller-supplied pool before validating it against bp->max_vnics, and
before checking bp->vnic_info was even allocated yet (it is NULL
until the port is started). The existing "if (!vnic)" check was
always false, since vnic held the address of an array element and
is never NULL. Reorder to check dev_started/vnic_info first, then
bounds-check pool against max_vnics before indexing.
- bnxt_flow_non_void_item()/bnxt_flow_non_void_action() looped
unconditionally until a non-VOID item/action was found, walking off
the end of a pattern/actions array that lacked a terminating END
item. Bound the skip loop and stop advancing once the limit is hit.
Fixes: 51fafb89a9a ("net/bnxt: get rid of ff pools and use VNIC info array")
Fixes: 5c1171c972 ("net/bnxt: refactor filter/flow")
Cc: stable@dpdk.org
Signed-off-by: Chenna Arnoori <chenna.arnoori@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_ethdev.c | 16 ++++++++++------
drivers/net/bnxt/bnxt_flow.c | 28 ++++++++++++++++++++--------
2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 27cf67c04f..db9b49238a 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -2113,7 +2113,7 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
uint32_t index, uint32_t pool)
{
struct bnxt *bp = eth_dev->data->dev_private;
- struct bnxt_vnic_info *vnic = &bp->vnic_info[pool];
+ struct bnxt_vnic_info *vnic;
int rc = 0;
rc = is_bnxt_in_error(bp);
@@ -2125,15 +2125,19 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
return -ENOTSUP;
}
- if (!vnic) {
- PMD_DRV_LOG_LINE(ERR, "VNIC not found for pool %d!", pool);
- return -EINVAL;
- }
-
/* Filter settings will get applied when port is started */
if (!eth_dev->data->dev_started)
return 0;
+ if (bp->vnic_info == NULL)
+ return 0;
+
+ if (pool >= bp->max_vnics) {
+ PMD_DRV_LOG_LINE(ERR, "Pool %u exceeds VNIC count %u!", pool, bp->max_vnics);
+ return -EINVAL;
+ }
+ vnic = &bp->vnic_info[pool];
+
rc = bnxt_add_mac_filter(bp, vnic, mac_addr, index, pool);
return rc;
diff --git a/drivers/net/bnxt/bnxt_flow.c b/drivers/net/bnxt/bnxt_flow.c
index a2e590540b..14d52e1818 100644
--- a/drivers/net/bnxt/bnxt_flow.c
+++ b/drivers/net/bnxt/bnxt_flow.c
@@ -58,24 +58,36 @@ bnxt_flow_args_validate(const struct rte_flow_attr *attr,
return 0;
}
+#define BNXT_MAX_FLOW_ITEMS 256
+
static const struct rte_flow_item *
bnxt_flow_non_void_item(const struct rte_flow_item *cur)
{
- while (1) {
- if (cur->type != RTE_FLOW_ITEM_TYPE_VOID)
- return cur;
+ int i = 0;
+
+ if (!cur)
+ return NULL;
+
+ while (cur->type == RTE_FLOW_ITEM_TYPE_VOID && i < BNXT_MAX_FLOW_ITEMS) {
cur++;
+ i++;
}
+ return cur;
}
static const struct rte_flow_action *
bnxt_flow_non_void_action(const struct rte_flow_action *cur)
{
- while (1) {
- if (cur->type != RTE_FLOW_ACTION_TYPE_VOID)
- return cur;
+ int i = 0;
+
+ if (!cur)
+ return NULL;
+
+ while (cur->type == RTE_FLOW_ACTION_TYPE_VOID && i < BNXT_MAX_FLOW_ITEMS) {
cur++;
+ i++;
}
+ return cur;
}
static int
@@ -109,7 +121,7 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[],
PMD_DRV_LOG_LINE(DEBUG, "Unknown Flow type");
use_ntuple |= 0;
}
- item++;
+ item = bnxt_flow_non_void_item(item + 1);
}
if (has_vlan && use_ntuple) {
@@ -680,7 +692,7 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_attr *attr,
default:
break;
}
- item++;
+ item = bnxt_flow_non_void_item(item + 1);
}
filter->enables = en;
filter->valid_flags = valid_flags;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (3 preceding siblings ...)
2026-09-18 3:27 ` [PATCH 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
@ 2026-09-18 3:27 ` Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
6 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-18 3:27 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, stable, Mohammad Shuab Siddique
From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Three independent out-of-bounds issues:
- bnxt_rx_pkt() incremented tpa_info->agg_count and indexed
tpa_info->agg_arr[] with only an RTE_ASSERT (compiled out in release
builds) guarding the array bound, allowing an out-of-bounds write if
firmware sent more aggregation segments than TPA_MAX_NUM_SEGS.
- bnxt_rx_descriptor_status_op() used the firmware-supplied completion
opaque value directly as an rx_buf_ring[] index without masking it to
the ring size first.
- bnxt_hwrm_func_vf_vnic_query() returned the firmware-reported
vnic_id_cnt unclamped; a value exceeding bp->pf->total_vnics would
cause the caller to iterate past the end of its VNIC ID buffer.
Fixes: b150a7e7ee ("net/bnxt: support LRO on Thor adapters")
Fixes: 0fe613bb87 ("net/bnxt: support Rx descriptor status")
Fixes: cbcd375d37 ("net/bnxt: fix HWRM macros and locking")
Cc: stable@dpdk.org
Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_ethdev.c | 3 ++-
drivers/net/bnxt/bnxt_hwrm.c | 3 ++-
drivers/net/bnxt/bnxt_rxr.c | 10 +++++++++-
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index db9b49238a..d21ebac0c2 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -3631,7 +3631,8 @@ bnxt_rx_descriptor_status_op(void *rx_queue, uint16_t offset)
case CMPL_BASE_TYPE_RX_L2:
case CMPL_BASE_TYPE_RX_L2_V2:
if (desc == offset) {
- cons = rxcmp->opaque;
+ cons = RING_IDX(rxr->rx_ring_struct,
+ rxcmp->opaque);
if (rxr->rx_buf_ring[cons])
return RTE_ETH_RX_DESC_DONE;
else
diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 0143da8789..aae50c1fea 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -6242,7 +6242,8 @@ static int bnxt_hwrm_func_vf_vnic_query(struct bnxt *bp, uint16_t vf,
}
rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB);
HWRM_CHECK_RESULT();
- rc = rte_le_to_cpu_32(resp->vnic_id_cnt);
+ rc = RTE_MIN(rte_le_to_cpu_32(resp->vnic_id_cnt),
+ (uint32_t)bp->pf->total_vnics);
HWRM_UNLOCK();
diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c
index 87640eaa79..cd4e93bdb3 100644
--- a/drivers/net/bnxt/bnxt_rxr.c
+++ b/drivers/net/bnxt/bnxt_rxr.c
@@ -1164,7 +1164,15 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt,
}
tpa_info = &rxr->tpa_info[agg_id];
- RTE_ASSERT(tpa_info->agg_count < 16);
+ if (unlikely(tpa_info->agg_count >= TPA_MAX_NUM_SEGS)) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA abuf: agg_count %u exceeds max %u",
+ tpa_info->agg_count, TPA_MAX_NUM_SEGS);
+ tpa_info->agg_count = 0;
+ bnxt_sched_ring_reset(rxq);
+ rc = -EINVAL;
+ goto next_rx;
+ }
tpa_info->agg_arr[tpa_info->agg_count++] = *rx_agg;
rc = -EINVAL; /* Continue w/o new mbuf */
goto next_rx;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (4 preceding siblings ...)
2026-09-18 3:27 ` [PATCH 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
@ 2026-09-21 2:24 ` Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
` (4 more replies)
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
6 siblings, 5 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-21 2:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Mohammad Shuab Siddique
From: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
This series fixes five independent out-of-bounds issues in flow,
Rx-datapath and naming code in the bnxt PMD:
- two stack-allocated variable-length arrays in flow-stats sizing
that risked stack exhaustion,
- a TPA aggregation ID read from a completion and used to index
rxr->tpa_info[] without a bounds check,
- three separate sprintf() calls into fixed-size buffers with no
bound on the formatted string length, plus four related bugs
(a leak, a stale flag, and two locks left held) introduced by
this change's own new early-return paths and fixed here,
- a caller-supplied MAC pool index used before being validated
against bp->max_vnics, and an unbounded flow item/action skip
loop that could walk off the end of the pattern array, and
- a firmware-supplied Rx completion opaque value used unmasked as
an rx_buf_ring[] index, an aggregation-segment count guarded only
by a release-mode-compiled-out RTE_ASSERT, and an unclamped VF
VNIC-count from firmware.
Each patch is independently bisectable and was validated with a
scoped net/bnxt build (and, for split points, an intermediate-commit
build) in addition to the full compliance gate.
v2:
* Patch 2/5 ("fix bounds on TPA aggregation ID from completions"):
corrected its Fixes: tag SHA1s to the full 12-character form, and
fixed a real bug an AI-review pass caught -- the legacy (non-Thor)
TPA end path's new bounds-check-failure branch wasn't draining
pending aggregation-buffer completions before returning, unlike
the sibling in_reset early return right above it, which could
desync the CQ consumer index. See that patch's own changelog.
* Patch 3/5 ("harden sprintf bounds for device memory names"): fixed
a real bug an AI-review pass caught -- bnxt_hwrm_ver_get()'s new
early return on a snprintf failure also skipped HWRM_UNLOCK(),
unlike this same function's other error exits and the sibling
cfa_pair_*() fixes in this same patch, which would leak
bp->hwrm_lock and deadlock every later HWRM call. See that patch's
own changelog.
* Patch 4/5 ("fix bounds in MAC pool index and flow parsing"): fixed
both Fixes: tag SHA1s to the full 12-character form.
* Patch 5/5 ("fix TPA agg Rx descriptor and VNIC query bounds"):
fixed all three Fixes: tag SHA1s to the full 12-character form.
Also addressed (no code change needed, see that patch's changelog)
a reviewer question about a possible leak in the agg_count-overflow
error path.
* Patch 1/5 is unchanged from v1.
Chenna Arnoori (1):
net/bnxt: fix bounds in MAC pool index and flow parsing
Joseph Wong (1):
net/bnxt: fix stack exhaustion in flow stats
Keegan Freyhof (1):
net/bnxt: harden sprintf bounds for device memory names
Kishore Padmanabha (1):
net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds
Mohammad Shuab Siddique (1):
net/bnxt: fix bounds on TPA aggregation ID from completions
drivers/net/bnxt/bnxt.h | 15 +++++++
drivers/net/bnxt/bnxt_ethdev.c | 43 +++++++++++++-------
drivers/net/bnxt/bnxt_flow.c | 28 +++++++++----
drivers/net/bnxt/bnxt_hwrm.c | 75 ++++++++++++++++++++++++++---------
drivers/net/bnxt/bnxt_rxr.c | 58 +++++++++++++++++++++-------
drivers/net/bnxt/bnxt_stats.c | 18 ++++-----
6 files changed, 175 insertions(+), 62 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v2 1/5] net/bnxt: fix stack exhaustion in flow stats
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
@ 2026-09-21 2:24 ` Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions Mohammad Shuab Siddique
` (3 subsequent siblings)
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-21 2:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Joseph Wong, stable, Mohammad Shuab Siddique
From: Joseph Wong <joseph.wong@broadcom.com>
In bnxt_flow_stats_cnt(), two variable-length arrays are allocated
on the stack. These arrays are allocated merely to be used to
calculate the dimensions via RTE_DIM(). Replace with the
mathematical equivalent to avoid potential stack exhaustion.
Fixes: 1e2f8aca2cc1 ("net/bnxt: fix allocation of flow stat related structs")
Cc: stable@dpdk.org
Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_stats.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index ba858710a5..c4efcb4b17 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -1095,12 +1095,8 @@ int bnxt_flow_stats_cnt(struct bnxt *bp)
{
if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
- BNXT_FLOW_XSTATS_EN(bp)) {
- struct bnxt_xstats_name_off flow_bytes[bp->max_l2_ctx];
- struct bnxt_xstats_name_off flow_pkts[bp->max_l2_ctx];
-
- return RTE_DIM(flow_bytes) + RTE_DIM(flow_pkts);
- }
+ BNXT_FLOW_XSTATS_EN(bp))
+ return 2 * bp->max_l2_ctx;
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v2 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
@ 2026-09-21 2:24 ` Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
` (2 subsequent siblings)
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-21 2:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Mohammad Shuab Siddique, stable
From: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
TPA start/end and TPA v2 abuf paths indexed rxr->tpa_info[] using
the aggregation ID from the completion without checking
BNXT_TPA_MAX_AGGS. Add bounds checks and schedule a ring reset on
failure. Also fix abuf aggregation ID decode to use
rte_le_to_cpu_16() when reading the device field.
Fixes: 0958d8b6435d ("net/bnxt: support LRO")
Fixes: b150a7e7ee66 ("net/bnxt: support LRO on Thor adapters")
Cc: stable@dpdk.org
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
v2:
* Real bug found during v2 review: on the legacy (non-Thor) TPA end
path, the new agg_id bounds-check-failure branch returned without
draining the pending aggregation-buffer completions, unlike the
sibling in_reset early return a few lines above it -- this would
leave the CQ raw_cons out of sync with the ring even after the
scheduled reset. Added the same bnxt_discard_rx() call the sibling
path already uses.
drivers/net/bnxt/bnxt_rxr.c | 48 ++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c
index 0fab4ddf78..87640eaa79 100644
--- a/drivers/net/bnxt/bnxt_rxr.c
+++ b/drivers/net/bnxt/bnxt_rxr.c
@@ -236,12 +236,19 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
struct rx_tpa_start_cmpl_hi *tpa_start1)
{
struct bnxt_rx_ring_info *rxr = rxq->rx_ring;
- uint16_t agg_id;
- uint16_t data_cons;
struct bnxt_tpa_info *tpa_info;
+ uint32_t data_cons, agg_id;
+ struct bnxt *bp = rxq->bp;
struct rte_mbuf *mbuf;
- agg_id = bnxt_tpa_start_agg_id(rxq->bp, tpa_start);
+ agg_id = bnxt_tpa_start_agg_id(bp, tpa_start);
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA start: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ return;
+ }
data_cons = tpa_start->opaque;
tpa_info = &rxr->tpa_info[agg_id];
@@ -268,7 +275,7 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
mbuf->port = rxq->port_id;
mbuf->ol_flags = RTE_MBUF_F_RX_LRO;
- bnxt_tpa_get_metadata(rxq->bp, tpa_info, tpa_start, tpa_start1);
+ bnxt_tpa_get_metadata(bp, tpa_info, tpa_start, tpa_start1);
if (likely(tpa_info->hash_valid)) {
mbuf->hash.rss = tpa_info->rss_hash;
@@ -278,7 +285,7 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
mbuf->ol_flags |= RTE_MBUF_F_RX_FDIR | RTE_MBUF_F_RX_FDIR_ID;
}
- if (tpa_info->vlan_valid && BNXT_RX_VLAN_STRIP_EN(rxq->bp)) {
+ if (tpa_info->vlan_valid && BNXT_RX_VLAN_STRIP_EN(bp)) {
mbuf->vlan_tci = tpa_info->vlan;
mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
}
@@ -421,20 +428,21 @@ static inline struct rte_mbuf *bnxt_tpa_end(
{
struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
struct bnxt_rx_ring_info *rxr = rxq->rx_ring;
- uint16_t agg_id;
+ struct bnxt_tpa_info *tpa_info;
+ struct bnxt *bp = rxq->bp;
+ uint8_t payload_offset;
struct rte_mbuf *mbuf;
uint8_t agg_bufs;
- uint8_t payload_offset;
- struct bnxt_tpa_info *tpa_info;
+ uint32_t agg_id;
if (unlikely(rxq->in_reset)) {
PMD_DRV_LOG_LINE(ERR, "rxq->in_reset: raw_cp_cons:%d",
*raw_cp_cons);
- bnxt_discard_rx(rxq->bp, cpr, raw_cp_cons, tpa_end);
+ bnxt_discard_rx(bp, cpr, raw_cp_cons, tpa_end);
return NULL;
}
- if (BNXT_CHIP_P5_P7(rxq->bp)) {
+ if (BNXT_CHIP_P5_P7(bp)) {
struct rx_tpa_v2_end_cmpl *th_tpa_end;
struct rx_tpa_v2_end_cmpl_hi *th_tpa_end1;
@@ -451,6 +459,15 @@ static inline struct rte_mbuf *bnxt_tpa_end(
payload_offset = tpa_end->payload_offset;
}
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA end: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_discard_rx(bp, cpr, raw_cp_cons, tpa_end);
+ bnxt_sched_ring_reset(rxq);
+ return NULL;
+ }
+
tpa_info = &rxr->tpa_info[agg_id];
mbuf = tpa_info->mbuf;
RTE_ASSERT(mbuf != NULL);
@@ -1135,9 +1152,18 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt,
if (cmp_type == RX_TPA_V2_ABUF_CMPL_TYPE_RX_TPA_AGG) {
struct rx_tpa_v2_abuf_cmpl *rx_agg = (void *)rxcmp;
- uint16_t agg_id = rte_cpu_to_le_16(rx_agg->agg_id);
+ uint32_t agg_id = rte_le_to_cpu_16(rx_agg->agg_id);
struct bnxt_tpa_info *tpa_info;
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA abuf: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ rc = -EINVAL;
+ goto next_rx;
+ }
+
tpa_info = &rxr->tpa_info[agg_id];
RTE_ASSERT(tpa_info->agg_count < 16);
tpa_info->agg_arr[tpa_info->agg_count++] = *rx_agg;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory names
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions Mohammad Shuab Siddique
@ 2026-09-21 2:24 ` Mohammad Shuab Siddique
2026-09-21 15:49 ` Stephen Hemminger
2026-09-21 2:24 ` [PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
4 siblings, 1 reply; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-21 2:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Keegan Freyhof, Mohammad Shuab Siddique
From: Keegan Freyhof <keegan.freyhof@broadcom.com>
sprintf() into fixed-size stack buffers such as
char type[RTE_MEMZONE_NAMESIZE] does not bound the write to the
buffer, so a long enough formatted string (e.g. from PCI address
fields) overflows it.
Add check_snprintf_rc(), a helper that logs and returns an error on a
failed snprintf() call and logs (without failing) a truncated one.
Convert sprintf() calls building a memzone/malloc name to snprintf()
plus this check, and add the same check to the existing snprintf()
calls building HWRM CFA pair_name request fields. Unlike a truncated
memzone/malloc label, a truncated pair_name would be sent to firmware
and could match the wrong pair or none at all, so
bnxt_hwrm_cfa_pair_exists()/_alloc()/_free() additionally reject a
truncated pair_name outright instead of proceeding.
Three bugs introduced by this change and fixed here: in
bnxt_hwrm_ver_get(), free bp->hwrm_short_cmd_req_addr (and null it)
before checking the new snprintf's return, instead of after, so an
early return on a snprintf failure doesn't leak the previous
allocation; also clear BNXT_FLAG_SHORT_CMD on that same early return,
since it may already have been set a few lines above and would
otherwise claim short-command support with no buffer allocated. In
bnxt_hwrm_cfa_pair_exists()/_alloc()/_free(), the new early-return
paths exited without releasing bp->hwrm_lock (held since the
preceding HWRM_PREP()), which would deadlock every later HWRM call;
added the missing HWRM_UNLOCK() before each return.
Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <shuab.siddique@broadcom.com>
---
v2:
* Fixed three bugs the v1 diff itself introduced, found in a second
review pass: in bnxt_hwrm_ver_get(), free/null
bp->hwrm_short_cmd_req_addr and clear BNXT_FLAG_SHORT_CMD before
(not after) checking the new snprintf's return, so an early return
on failure doesn't leak the previous allocation or leave the flag
claiming short-command support with no buffer behind it; in
bnxt_hwrm_cfa_pair_exists()/_alloc()/_free(), added the missing
HWRM_UNLOCK() on the new early-return paths, which previously
exited holding bp->hwrm_lock and would deadlock every later HWRM
call.
---
drivers/net/bnxt/bnxt.h | 15 +++++++
drivers/net/bnxt/bnxt_ethdev.c | 24 ++++++++----
drivers/net/bnxt/bnxt_hwrm.c | 72 +++++++++++++++++++++++++---------
drivers/net/bnxt/bnxt_stats.c | 10 +++--
4 files changed, 93 insertions(+), 28 deletions(-)
diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h
index 69455af31f9..ad0d5fe5dba 100644
--- a/drivers/net/bnxt/bnxt.h
+++ b/drivers/net/bnxt/bnxt.h
@@ -1288,6 +1288,21 @@ extern int bnxt_logtype_driver;
BNXT_LINK_SPEEDS_V2_VF((bp))))
#define BNXT_MAX_SPEED_LANES 8
#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_P5_P7(bp) || (bp)->max_tpa_v2)
+
+static inline int
+check_snprintf_rc(int rc, size_t max_size, const char *ctx)
+{
+ if (rc < 0) {
+ PMD_DRV_LOG_LINE(ERR, "Error when creating string for %s", ctx);
+ return rc;
+ }
+
+ if (rc >= (int)max_size)
+ PMD_DRV_LOG_LINE(INFO, "String truncated when creating string for %s", ctx);
+
+ return 0;
+}
+
extern const struct rte_flow_ops bnxt_ulp_rte_flow_ops;
int32_t bnxt_ulp_port_init(struct bnxt *bp);
void bnxt_ulp_port_deinit(struct bnxt *bp);
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index eefd99464e9..7b9d1c862d8 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -647,13 +647,15 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
{
struct rte_pci_device *pdev = bp->pdev;
char type[RTE_MEMZONE_NAMESIZE];
+ int rc = 0, snp_rc = 0;
uint16_t max_fc;
- int rc = 0;
max_fc = bp->flow_stat->max_fc;
- sprintf(type, "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_rx_fc_in_") < 0)
+ return snp_rc;
/* 4 bytes for each counter-id */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 4,
@@ -661,8 +663,10 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_rx_fc_out_") < 0)
+ return snp_rc;
/* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 16,
@@ -670,8 +674,10 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_tx_fc_in_") < 0)
+ return snp_rc;
/* 4 bytes for each counter-id */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 4,
@@ -679,8 +685,10 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+ snp_rc = snprintf(type, sizeof(type), "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_tx_fc_out_") < 0)
+ return snp_rc;
/* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
max_fc * 16,
@@ -5226,8 +5234,8 @@ int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp)
{
struct bnxt_ctx_mem_info *ctx = bp->ctx;
struct bnxt_ctx_mem *ctx2;
+ int rc = 0, snp_rc = 0;
uint16_t type;
- int rc = 0;
ctx2 = &ctx->ctx_arr[0];
for (type = 0; type < ctx->types && rc == 0; type++) {
@@ -5248,7 +5256,9 @@ int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp)
for (i = 0; i < w && rc == 0; i++) {
char name[RTE_MEMZONE_NAMESIZE] = {0};
- sprintf(name, "_%d_%d", i, type);
+ snp_rc = snprintf(name, sizeof(name), "_%d_%d", i, type);
+ if (check_snprintf_rc(snp_rc, sizeof(name), "index and type.") < 0)
+ return snp_rc;
if (ctxm->entry_multiple)
entries = bnxt_roundup(ctxm->max_entries,
diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 4e50ff7e1e0..7719084a6d3 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -1591,12 +1591,12 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp)
int bnxt_hwrm_ver_get(struct bnxt *bp, uint32_t timeout)
{
- int rc = 0;
struct hwrm_ver_get_input req = {.req_type = 0 };
struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr;
uint32_t fw_version;
uint16_t max_resp_len;
char type[RTE_MEMZONE_NAMESIZE];
+ int rc = 0, snp_rc = 0;
uint32_t dev_caps_cfg;
bp->max_req_len = HWRM_MAX_REQ_LEN;
@@ -1677,11 +1677,16 @@ int bnxt_hwrm_ver_get(struct bnxt *bp, uint32_t timeout)
(dev_caps_cfg &
HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED)) ||
bp->hwrm_max_ext_req_len > HWRM_MAX_REQ_LEN) {
- sprintf(type, "bnxt_hwrm_short_" PCI_PRI_FMT,
- bp->pdev->addr.domain, bp->pdev->addr.bus,
- bp->pdev->addr.devid, bp->pdev->addr.function);
-
+ snp_rc = snprintf(type, sizeof(type), "bnxt_hwrm_short_" PCI_PRI_FMT,
+ bp->pdev->addr.domain, bp->pdev->addr.bus,
+ bp->pdev->addr.devid, bp->pdev->addr.function);
rte_free(bp->hwrm_short_cmd_req_addr);
+ bp->hwrm_short_cmd_req_addr = NULL;
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_hwrm_short_") < 0) {
+ bp->flags &= ~BNXT_FLAG_SHORT_CMD;
+ rc = snp_rc;
+ goto error;
+ }
bp->hwrm_short_cmd_req_addr =
rte_malloc(type, bp->hwrm_max_ext_req_len, 0);
@@ -3526,9 +3531,12 @@ int bnxt_alloc_hwrm_resources(struct bnxt *bp)
{
struct rte_pci_device *pdev = bp->pdev;
char type[RTE_MEMZONE_NAMESIZE];
+ int snp_rc = 0;
- sprintf(type, "bnxt_hwrm_" PCI_PRI_FMT, pdev->addr.domain,
- pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ snp_rc = snprintf(type, sizeof(type), "bnxt_hwrm_" PCI_PRI_FMT, pdev->addr.domain,
+ pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
+ if (check_snprintf_rc(snp_rc, sizeof(type), "bnxt_hwrm_") < 0)
+ return snp_rc;
bp->max_resp_len = BNXT_PAGE_SIZE;
bp->hwrm_cmd_resp_addr = rte_malloc(type, bp->max_resp_len, 0);
if (bp->hwrm_cmd_resp_addr == NULL)
@@ -6769,6 +6777,7 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp)
{
struct bnxt_ctx_mem_info *ctx = bp->ctx;
char name[RTE_MEMZONE_NAMESIZE];
+ int snp_rc = 0;
uint16_t type;
for (type = 0; type < ctx->types; type++) {
@@ -6781,8 +6790,10 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp)
if (ctxm->instance_bmap)
n = bnxt_hweight32(ctxm->instance_bmap);
- sprintf(name, "bnxt_ctx_pgmem_%d_%d",
- bp->eth_dev->data->port_id, type);
+ snp_rc = snprintf(name, sizeof(name), "bnxt_ctx_pgmem_%d_%d",
+ bp->eth_dev->data->port_id, type);
+ if (check_snprintf_rc(snp_rc, sizeof(name), "bnxt_ctx_pgmem_") < 0)
+ return snp_rc;
ctxm->pg_info = rte_malloc(name, sizeof(*ctxm->pg_info) * n,
RTE_CACHE_LINE_SIZE);
if (!ctxm->pg_info)
@@ -7740,7 +7751,7 @@ int bnxt_hwrm_cfa_pair_exists(struct bnxt *bp, struct bnxt_representor *rep_bp)
{
struct hwrm_cfa_pair_info_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_cfa_pair_info_input req = {0};
- int rc = 0;
+ int rc = 0, snp_rc = 0;
if (!(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp))) {
PMD_DRV_LOG_LINE(DEBUG,
@@ -7749,8 +7760,16 @@ int bnxt_hwrm_cfa_pair_exists(struct bnxt *bp, struct bnxt_representor *rep_bp)
}
HWRM_PREP(&req, HWRM_CFA_PAIR_INFO, BNXT_USE_CHIMP_MB);
- snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
- bp->eth_dev->data->name, rep_bp->vf_id);
+ snp_rc = snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
+ bp->eth_dev->data->name, rep_bp->vf_id);
+ if (check_snprintf_rc(snp_rc, sizeof(req.pair_name), "svfr") < 0) {
+ HWRM_UNLOCK();
+ return snp_rc;
+ }
+ if (snp_rc >= (int)sizeof(req.pair_name)) {
+ HWRM_UNLOCK();
+ return -EINVAL;
+ }
req.flags =
rte_cpu_to_le_32(HWRM_CFA_PAIR_INFO_INPUT_FLAGS_LOOKUP_TYPE);
@@ -7768,7 +7787,7 @@ int bnxt_hwrm_cfa_pair_alloc(struct bnxt *bp, struct bnxt_representor *rep_bp)
{
struct hwrm_cfa_pair_alloc_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_cfa_pair_alloc_input req = {0};
- int rc;
+ int rc, snp_rc = 0;
if (!(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp))) {
PMD_DRV_LOG_LINE(DEBUG,
@@ -7778,8 +7797,16 @@ int bnxt_hwrm_cfa_pair_alloc(struct bnxt *bp, struct bnxt_representor *rep_bp)
HWRM_PREP(&req, HWRM_CFA_PAIR_ALLOC, BNXT_USE_CHIMP_MB);
req.pair_mode = HWRM_CFA_PAIR_FREE_INPUT_PAIR_MODE_REP2FN_TRUFLOW;
- snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
- bp->eth_dev->data->name, rep_bp->vf_id);
+ snp_rc = snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
+ bp->eth_dev->data->name, rep_bp->vf_id);
+ if (check_snprintf_rc(snp_rc, sizeof(req.pair_name), "svfr") < 0) {
+ HWRM_UNLOCK();
+ return snp_rc;
+ }
+ if (snp_rc >= (int)sizeof(req.pair_name)) {
+ HWRM_UNLOCK();
+ return -EINVAL;
+ }
req.pf_b_id = rep_bp->parent_pf_idx;
req.vf_b_id = BNXT_REP_PF(rep_bp) ? rte_cpu_to_le_16(((uint16_t)-1)) :
@@ -7814,7 +7841,7 @@ int bnxt_hwrm_cfa_pair_free(struct bnxt *bp, struct bnxt_representor *rep_bp)
{
struct hwrm_cfa_pair_free_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_cfa_pair_free_input req = {0};
- int rc;
+ int rc, snp_rc = 0;
if (!(BNXT_PF(bp) || BNXT_VF_IS_TRUSTED(bp))) {
PMD_DRV_LOG_LINE(DEBUG,
@@ -7823,8 +7850,17 @@ int bnxt_hwrm_cfa_pair_free(struct bnxt *bp, struct bnxt_representor *rep_bp)
}
HWRM_PREP(&req, HWRM_CFA_PAIR_FREE, BNXT_USE_CHIMP_MB);
- snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
- bp->eth_dev->data->name, rep_bp->vf_id);
+ snp_rc = snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
+ bp->eth_dev->data->name, rep_bp->vf_id);
+ if (check_snprintf_rc(snp_rc, sizeof(req.pair_name), "svfr") < 0) {
+ HWRM_UNLOCK();
+ return snp_rc;
+ }
+ if (snp_rc >= (int)sizeof(req.pair_name)) {
+ HWRM_UNLOCK();
+ return -EINVAL;
+ }
+
req.pf_b_id = rep_bp->parent_pf_idx;
req.pair_mode = HWRM_CFA_PAIR_FREE_INPUT_PAIR_MODE_REP2FN_TRUFLOW;
req.vf_id = BNXT_REP_PF(rep_bp) ? rte_cpu_to_le_16(((uint16_t)-1)) :
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index c4efcb4b179..19153f96ae6 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -1108,7 +1108,7 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
struct bnxt *bp = (struct bnxt *)eth_dev->data->dev_private;
unsigned int stat_cnt;
unsigned int i, count = 0, sz;
- int rc;
+ int rc, snp_rc = 0;
rc = is_bnxt_in_error(bp);
if (rc)
@@ -1183,12 +1183,16 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
for (i = 0; i < bp->max_l2_ctx; i++) {
char buf[RTE_ETH_XSTATS_NAME_SIZE];
- sprintf(buf, "flow_%d_bytes", i);
+ snp_rc = snprintf(buf, sizeof(buf), "flow_%d_bytes", i);
+ if (check_snprintf_rc(snp_rc, sizeof(buf), "flow_%d_bytes") < 0)
+ return snp_rc;
strlcpy(xstats_names[count].name, buf,
sizeof(xstats_names[count].name));
count++;
- sprintf(buf, "flow_%d_packets", i);
+ snp_rc = snprintf(buf, sizeof(buf), "flow_%d_packets", i);
+ if (check_snprintf_rc(snp_rc, sizeof(buf), "flow_%d_packets") < 0)
+ return snp_rc;
strlcpy(xstats_names[count].name, buf,
sizeof(xstats_names[count].name));
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (2 preceding siblings ...)
2026-09-21 2:24 ` [PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
@ 2026-09-21 2:24 ` Mohammad Shuab Siddique
2026-09-21 15:50 ` Stephen Hemminger
2026-09-21 2:24 ` [PATCH v2 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
4 siblings, 1 reply; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-21 2:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Chenna Arnoori, stable,
Mohammad Shuab Siddique
From: Chenna Arnoori <chenna.arnoori@broadcom.com>
Two independent out-of-bounds issues in the driver:
- bnxt_mac_addr_add_op() indexed bp->vnic_info[pool] with a
caller-supplied pool before validating it against bp->max_vnics, and
before checking bp->vnic_info was even allocated yet (it is NULL
until the port is started). The existing "if (!vnic)" check was
always false, since vnic held the address of an array element and
is never NULL. Reorder to check dev_started/vnic_info first, then
bounds-check pool against max_vnics before indexing.
- bnxt_flow_non_void_item()/bnxt_flow_non_void_action() looped
unconditionally until a non-VOID item/action was found, walking off
the end of a pattern/actions array that lacked a terminating END
item. Bound the skip loop and stop advancing once the limit is hit.
Fixes: 51fafb89a9a0 ("net/bnxt: get rid of ff pools and use VNIC info array")
Fixes: 5c1171c97216 ("net/bnxt: refactor filter/flow")
Cc: stable@dpdk.org
Signed-off-by: Chenna Arnoori <chenna.arnoori@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_ethdev.c | 16 ++++++++++------
drivers/net/bnxt/bnxt_flow.c | 28 ++++++++++++++++++++--------
2 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 27cf67c04f..db9b49238a 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -2113,7 +2113,7 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
uint32_t index, uint32_t pool)
{
struct bnxt *bp = eth_dev->data->dev_private;
- struct bnxt_vnic_info *vnic = &bp->vnic_info[pool];
+ struct bnxt_vnic_info *vnic;
int rc = 0;
rc = is_bnxt_in_error(bp);
@@ -2125,15 +2125,19 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
return -ENOTSUP;
}
- if (!vnic) {
- PMD_DRV_LOG_LINE(ERR, "VNIC not found for pool %d!", pool);
- return -EINVAL;
- }
-
/* Filter settings will get applied when port is started */
if (!eth_dev->data->dev_started)
return 0;
+ if (bp->vnic_info == NULL)
+ return 0;
+
+ if (pool >= bp->max_vnics) {
+ PMD_DRV_LOG_LINE(ERR, "Pool %u exceeds VNIC count %u!", pool, bp->max_vnics);
+ return -EINVAL;
+ }
+ vnic = &bp->vnic_info[pool];
+
rc = bnxt_add_mac_filter(bp, vnic, mac_addr, index, pool);
return rc;
diff --git a/drivers/net/bnxt/bnxt_flow.c b/drivers/net/bnxt/bnxt_flow.c
index a2e590540b..14d52e1818 100644
--- a/drivers/net/bnxt/bnxt_flow.c
+++ b/drivers/net/bnxt/bnxt_flow.c
@@ -58,24 +58,36 @@ bnxt_flow_args_validate(const struct rte_flow_attr *attr,
return 0;
}
+#define BNXT_MAX_FLOW_ITEMS 256
+
static const struct rte_flow_item *
bnxt_flow_non_void_item(const struct rte_flow_item *cur)
{
- while (1) {
- if (cur->type != RTE_FLOW_ITEM_TYPE_VOID)
- return cur;
+ int i = 0;
+
+ if (!cur)
+ return NULL;
+
+ while (cur->type == RTE_FLOW_ITEM_TYPE_VOID && i < BNXT_MAX_FLOW_ITEMS) {
cur++;
+ i++;
}
+ return cur;
}
static const struct rte_flow_action *
bnxt_flow_non_void_action(const struct rte_flow_action *cur)
{
- while (1) {
- if (cur->type != RTE_FLOW_ACTION_TYPE_VOID)
- return cur;
+ int i = 0;
+
+ if (!cur)
+ return NULL;
+
+ while (cur->type == RTE_FLOW_ACTION_TYPE_VOID && i < BNXT_MAX_FLOW_ITEMS) {
cur++;
+ i++;
}
+ return cur;
}
static int
@@ -109,7 +121,7 @@ bnxt_filter_type_check(const struct rte_flow_item pattern[],
PMD_DRV_LOG_LINE(DEBUG, "Unknown Flow type");
use_ntuple |= 0;
}
- item++;
+ item = bnxt_flow_non_void_item(item + 1);
}
if (has_vlan && use_ntuple) {
@@ -680,7 +692,7 @@ bnxt_validate_and_parse_flow_type(const struct rte_flow_attr *attr,
default:
break;
}
- item++;
+ item = bnxt_flow_non_void_item(item + 1);
}
filter->enables = en;
filter->valid_flags = valid_flags;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v2 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (3 preceding siblings ...)
2026-09-21 2:24 ` [PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
@ 2026-09-21 2:24 ` Mohammad Shuab Siddique
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-21 2:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, stable, Mohammad Shuab Siddique
From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Three independent out-of-bounds issues:
- bnxt_rx_pkt() incremented tpa_info->agg_count and indexed
tpa_info->agg_arr[] with only an RTE_ASSERT (compiled out in release
builds) guarding the array bound, allowing an out-of-bounds write if
firmware sent more aggregation segments than TPA_MAX_NUM_SEGS.
- bnxt_rx_descriptor_status_op() used the firmware-supplied completion
opaque value directly as an rx_buf_ring[] index without masking it to
the ring size first.
- bnxt_hwrm_func_vf_vnic_query() returned the firmware-reported
vnic_id_cnt unclamped; a value exceeding bp->pf->total_vnics would
cause the caller to iterate past the end of its VNIC ID buffer.
Fixes: b150a7e7ee66 ("net/bnxt: support LRO on Thor adapters")
Fixes: 0fe613bb87b2 ("net/bnxt: support Rx descriptor status")
Fixes: cbcd375d37d2 ("net/bnxt: fix HWRM macros and locking")
Cc: stable@dpdk.org
Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_ethdev.c | 3 ++-
drivers/net/bnxt/bnxt_hwrm.c | 3 ++-
drivers/net/bnxt/bnxt_rxr.c | 10 +++++++++-
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index db9b49238a..d21ebac0c2 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -3631,7 +3631,8 @@ bnxt_rx_descriptor_status_op(void *rx_queue, uint16_t offset)
case CMPL_BASE_TYPE_RX_L2:
case CMPL_BASE_TYPE_RX_L2_V2:
if (desc == offset) {
- cons = rxcmp->opaque;
+ cons = RING_IDX(rxr->rx_ring_struct,
+ rxcmp->opaque);
if (rxr->rx_buf_ring[cons])
return RTE_ETH_RX_DESC_DONE;
else
diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 0143da8789..aae50c1fea 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -6242,7 +6242,8 @@ static int bnxt_hwrm_func_vf_vnic_query(struct bnxt *bp, uint16_t vf,
}
rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB);
HWRM_CHECK_RESULT();
- rc = rte_le_to_cpu_32(resp->vnic_id_cnt);
+ rc = RTE_MIN(rte_le_to_cpu_32(resp->vnic_id_cnt),
+ (uint32_t)bp->pf->total_vnics);
HWRM_UNLOCK();
diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c
index 87640eaa79..cd4e93bdb3 100644
--- a/drivers/net/bnxt/bnxt_rxr.c
+++ b/drivers/net/bnxt/bnxt_rxr.c
@@ -1164,7 +1164,15 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt,
}
tpa_info = &rxr->tpa_info[agg_id];
- RTE_ASSERT(tpa_info->agg_count < 16);
+ if (unlikely(tpa_info->agg_count >= TPA_MAX_NUM_SEGS)) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA abuf: agg_count %u exceeds max %u",
+ tpa_info->agg_count, TPA_MAX_NUM_SEGS);
+ tpa_info->agg_count = 0;
+ bnxt_sched_ring_reset(rxq);
+ rc = -EINVAL;
+ goto next_rx;
+ }
tpa_info->agg_arr[tpa_info->agg_count++] = *rx_agg;
rc = -EINVAL; /* Continue w/o new mbuf */
goto next_rx;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory names
2026-09-21 2:24 ` [PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
@ 2026-09-21 15:49 ` Stephen Hemminger
0 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2026-09-21 15:49 UTC (permalink / raw)
To: Mohammad Shuab Siddique
Cc: dev, kishore.padmanabha, Keegan Freyhof, Mohammad Shuab Siddique
On Sun, 20 Sep 2026 20:24:18 -0600
Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com> wrote:
> From: Keegan Freyhof <keegan.freyhof@broadcom.com>
>
> sprintf() into fixed-size stack buffers such as
> char type[RTE_MEMZONE_NAMESIZE] does not bound the write to the
> buffer, so a long enough formatted string (e.g. from PCI address
> fields) overflows it.
>
> Add check_snprintf_rc(), a helper that logs and returns an error on a
> failed snprintf() call and logs (without failing) a truncated one.
> Convert sprintf() calls building a memzone/malloc name to snprintf()
> plus this check, and add the same check to the existing snprintf()
> calls building HWRM CFA pair_name request fields. Unlike a truncated
> memzone/malloc label, a truncated pair_name would be sent to firmware
> and could match the wrong pair or none at all, so
> bnxt_hwrm_cfa_pair_exists()/_alloc()/_free() additionally reject a
> truncated pair_name outright instead of proceeding.
>
> Three bugs introduced by this change and fixed here: in
> bnxt_hwrm_ver_get(), free bp->hwrm_short_cmd_req_addr (and null it)
> before checking the new snprintf's return, instead of after, so an
> early return on a snprintf failure doesn't leak the previous
> allocation; also clear BNXT_FLAG_SHORT_CMD on that same early return,
> since it may already have been set a few lines above and would
> otherwise claim short-command support with no buffer allocated. In
> bnxt_hwrm_cfa_pair_exists()/_alloc()/_free(), the new early-return
> paths exited without releasing bp->hwrm_lock (held since the
> preceding HWRM_PREP()), which would deadlock every later HWRM call;
> added the missing HWRM_UNLOCK() before each return.
>
> Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
> Signed-off-by: Mohammad Shuab Siddique <shuab.siddique@broadcom.com>
>
> ---
[PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory
names
Error: does not apply to main (see summary).
Warning: the rc < 0 branch of check_snprintf_rc() is unreachable.
snprintf() only fails on encoding errors, which cannot happen with
these formats. Every converted name except pair_name is an
rte_malloc()/rte_zmalloc_socket() type label. That label is
informational only, so truncation is harmless.
The only real overflow is a PCI domain above 0xffff with
"bnxt_hwrm_short_": 16 + 8 + 8 = 32 chars plus NUL into 32 bytes.
Plain snprintf() fixes that. Drop the helper and the early-return
paths, including the flag clearing and unlock handling added for
unreachable code.
For pair_name, rejecting truncation is reasonable. A single
"if (snprintf(...) >= sizeof(req.pair_name))" with HWRM_UNLOCK()
covers it.
Warning: the commit body carries review history ("Three bugs
introduced by this change and fixed here..."). Move it below ---.
Info: the flow xstat names can be written with snprintf() directly
into xstats_names[count].name, dropping buf and strlcpy(). "_%d_%d"
cannot exceed 32 bytes, so it needs no check.
Info: if the PCI domain overflow is the motivation, add Fixes: and
Cc: stable@dpdk.org.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing
2026-09-21 2:24 ` [PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
@ 2026-09-21 15:50 ` Stephen Hemminger
0 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2026-09-21 15:50 UTC (permalink / raw)
To: Mohammad Shuab Siddique; +Cc: dev, kishore.padmanabha, Chenna Arnoori, stable
On Sun, 20 Sep 2026 20:24:19 -0600
Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com> wrote:
> From: Chenna Arnoori <chenna.arnoori@broadcom.com>
>
> Two independent out-of-bounds issues in the driver:
>
> - bnxt_mac_addr_add_op() indexed bp->vnic_info[pool] with a
> caller-supplied pool before validating it against bp->max_vnics, and
> before checking bp->vnic_info was even allocated yet (it is NULL
> until the port is started). The existing "if (!vnic)" check was
> always false, since vnic held the address of an array element and
> is never NULL. Reorder to check dev_started/vnic_info first, then
> bounds-check pool against max_vnics before indexing.
>
> - bnxt_flow_non_void_item()/bnxt_flow_non_void_action() looped
> unconditionally until a non-VOID item/action was found, walking off
> the end of a pattern/actions array that lacked a terminating END
> item. Bound the skip loop and stop advancing once the limit is hit.
>
> Fixes: 51fafb89a9a0 ("net/bnxt: get rid of ff pools and use VNIC info array")
> Fixes: 5c1171c97216 ("net/bnxt: refactor filter/flow")
> Cc: stable@dpdk.org
>
> Signed-off-by: Chenna Arnoori <chenna.arnoori@broadcom.com>
> Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
> ---
[PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow
parsing
Warning: the bounded VOID skip does not bound the walk. The outer
loops in bnxt_filter_type_check() and
bnxt_validate_and_parse_flow_type() run while type != END. After 256
VOIDs the helper returns a VOID item, and the loop calls it again at
item + 1. A pattern without END is still walked off the end, and
non-VOID items are never counted. The rte_flow API requires the END
terminator. Drop this half of the patch.
The added "if (!cur) return NULL" paths return a value that no
caller checks.
Warning: in bnxt_mac_addr_add_op() the pool bounds check comes after
the dev_started early return. An invalid pool added while the port
is stopped returns 0, is recorded in mac_pool_sel, and then fails
later in bnxt_restore_mac_filters() at dev_start. Validate pool
against bp->max_vnics before the dev_started test. The
bp->vnic_info == NULL test after dev_started is dead code.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (5 preceding siblings ...)
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
@ 2026-09-29 0:24 ` Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
` (4 more replies)
6 siblings, 5 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-29 0:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Mohammad Shuab Siddique
From: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
This series fixes five independent out-of-bounds issues in flow,
Rx-datapath and naming code in the bnxt PMD:
- two stack-allocated variable-length arrays in flow-stats sizing
that risked stack exhaustion,
- a TPA aggregation ID read from a completion and used to index
rxr->tpa_info[] without a bounds check,
- sprintf() calls into fixed-size buffers with no bound on the
formatted string length,
- a caller-supplied MAC pool index used before being validated
against bp->max_vnics, and
- a firmware-supplied Rx completion opaque value used unmasked as
an rx_buf_ring[] index, an aggregation-segment count guarded only
by a release-mode-compiled-out RTE_ASSERT, and an unclamped VF
VNIC-count from firmware.
Each patch is independently bisectable and was validated with a
scoped net/bnxt build (and, for split points, an intermediate-commit
build) in addition to the full compliance gate.
v3:
* Patch 3/5 ("harden sprintf bounds for device memory names"):
dropped check_snprintf_rc() and the early-return paths on the CFA
pair_name sites entirely -- Stephen Hemminger noted the rc < 0
branch is unreachable and plain snprintf() is enough. See that
patch's own changelog.
* Patch 4/5: retitled from "fix bounds in MAC pool index and flow
parsing" to "fix bounds in MAC address pool index" and dropped the
flow-parsing half entirely -- Stephen Hemminger pointed out
rte_flow patterns/actions are always END-terminated by API
contract, so that bound guarded nothing reachable. Also reordered
the remaining fix to check pool-vs-max_vnics before dev_started.
See that patch's own changelog.
* Patches 1/5, 2/5 and 5/5 are unchanged from v2.
v2:
* Patch 2/5 ("fix bounds on TPA aggregation ID from completions"):
corrected its Fixes: tag SHA1s to the full 12-character form, and
fixed a real bug an AI-review pass caught -- the legacy (non-Thor)
TPA end path's new bounds-check-failure branch wasn't draining
pending aggregation-buffer completions before returning, unlike
the sibling in_reset early return right above it, which could
desync the CQ consumer index.
* Patch 3/5: fixed a real bug an AI-review pass caught --
bnxt_hwrm_ver_get()'s new early return on a snprintf failure also
skipped HWRM_UNLOCK(), which would leak bp->hwrm_lock and deadlock
every later HWRM call.
* Patch 4/5: fixed both Fixes: tag SHA1s to the full 12-character
form.
* Patch 5/5: fixed all three Fixes: tag SHA1s to the full
12-character form.
* Patch 1/5 is unchanged from v1.
Chenna Arnoori (1):
net/bnxt: fix bounds in MAC address pool index
Joseph Wong (1):
net/bnxt: fix stack exhaustion in flow stats
Keegan Freyhof (1):
net/bnxt: harden sprintf bounds for device memory names
Kishore Padmanabha (1):
net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds
Mohammad Shuab Siddique (1):
net/bnxt: validate TPA aggregation ID from completions
drivers/net/bnxt/bnxt.h | 1 +
drivers/net/bnxt/bnxt_ethdev.c | 28 +++++++++-------
drivers/net/bnxt/bnxt_flow.c | 1 +
drivers/net/bnxt/bnxt_hwrm.c | 13 ++++----
drivers/net/bnxt/bnxt_rxr.c | 58 +++++++++++++++++++++++++++-------
drivers/net/bnxt/bnxt_stats.c | 23 +++++---------
6 files changed, 80 insertions(+), 44 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH v3 1/5] net/bnxt: fix stack exhaustion in flow stats
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
@ 2026-09-29 0:24 ` Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 2/5] net/bnxt: validate TPA aggregation ID from completions Mohammad Shuab Siddique
` (3 subsequent siblings)
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-29 0:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Joseph Wong, stable, Mohammad Shuab Siddique
From: Joseph Wong <joseph.wong@broadcom.com>
In bnxt_flow_stats_cnt(), two variable-length arrays are allocated
on the stack. These arrays are allocated merely to be used to
calculate the dimensions via RTE_DIM(). Replace with the
mathematical equivalent to avoid potential stack exhaustion.
Fixes: 1e2f8aca2cc1 ("net/bnxt: fix allocation of flow stat related structs")
Cc: stable@dpdk.org
Signed-off-by: Joseph Wong <joseph.wong@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_stats.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index 37b33f0505..4074613eb0 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -1079,12 +1079,8 @@ int bnxt_flow_stats_cnt(struct bnxt *bp)
{
if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
- BNXT_FLOW_XSTATS_EN(bp)) {
- struct bnxt_xstats_name_off flow_bytes[bp->max_l2_ctx];
- struct bnxt_xstats_name_off flow_pkts[bp->max_l2_ctx];
-
- return RTE_DIM(flow_bytes) + RTE_DIM(flow_pkts);
- }
+ BNXT_FLOW_XSTATS_EN(bp))
+ return 2 * bp->max_l2_ctx;
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 2/5] net/bnxt: validate TPA aggregation ID from completions
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
@ 2026-09-29 0:24 ` Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
` (2 subsequent siblings)
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-29 0:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Mohammad Shuab Siddique, stable
From: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
TPA start/end and TPA v2 abuf paths indexed rxr->tpa_info[] using
the aggregation ID from the completion without checking
BNXT_TPA_MAX_AGGS. Add bounds checks and schedule a ring reset on
failure. Also fix abuf aggregation ID decode to use
rte_le_to_cpu_16() when reading the device field. On the legacy
(non-Thor) TPA end path, also discard the pending agg bufs before
returning on an invalid agg_id, matching the existing in_reset early
return a few lines above; otherwise those agg buf completions are
left unconsumed and the CQ raw_cons goes out of sync with the ring
even after the scheduled reset.
Fixes: 0958d8b6435d ("net/bnxt: support LRO")
Fixes: b150a7e7ee66 ("net/bnxt: support LRO on Thor adapters")
Cc: stable@dpdk.org
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_rxr.c | 48 ++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 11 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c
index 98bdbc136a..1790ce839f 100644
--- a/drivers/net/bnxt/bnxt_rxr.c
+++ b/drivers/net/bnxt/bnxt_rxr.c
@@ -227,12 +227,19 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
struct rx_tpa_start_cmpl_hi *tpa_start1)
{
struct bnxt_rx_ring_info *rxr = rxq->rx_ring;
- uint16_t agg_id;
- uint16_t data_cons;
struct bnxt_tpa_info *tpa_info;
+ uint32_t data_cons, agg_id;
+ struct bnxt *bp = rxq->bp;
struct rte_mbuf *mbuf;
- agg_id = bnxt_tpa_start_agg_id(rxq->bp, tpa_start);
+ agg_id = bnxt_tpa_start_agg_id(bp, tpa_start);
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA start: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ return;
+ }
data_cons = tpa_start->opaque;
tpa_info = &rxr->tpa_info[agg_id];
@@ -259,7 +266,7 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
mbuf->port = rxq->port_id;
mbuf->ol_flags = RTE_MBUF_F_RX_LRO;
- bnxt_tpa_get_metadata(rxq->bp, tpa_info, tpa_start, tpa_start1);
+ bnxt_tpa_get_metadata(bp, tpa_info, tpa_start, tpa_start1);
if (likely(tpa_info->hash_valid)) {
mbuf->hash.rss = tpa_info->rss_hash;
@@ -269,7 +276,7 @@ static void bnxt_tpa_start(struct bnxt_rx_queue *rxq,
mbuf->ol_flags |= RTE_MBUF_F_RX_FDIR | RTE_MBUF_F_RX_FDIR_ID;
}
- if (tpa_info->vlan_valid && BNXT_RX_VLAN_STRIP_EN(rxq->bp)) {
+ if (tpa_info->vlan_valid && BNXT_RX_VLAN_STRIP_EN(bp)) {
mbuf->vlan_tci = tpa_info->vlan;
mbuf->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED;
}
@@ -412,20 +419,21 @@ static inline struct rte_mbuf *bnxt_tpa_end(
{
struct bnxt_cp_ring_info *cpr = rxq->cp_ring;
struct bnxt_rx_ring_info *rxr = rxq->rx_ring;
- uint16_t agg_id;
+ struct bnxt_tpa_info *tpa_info;
+ struct bnxt *bp = rxq->bp;
+ uint8_t payload_offset;
struct rte_mbuf *mbuf;
uint8_t agg_bufs;
- uint8_t payload_offset;
- struct bnxt_tpa_info *tpa_info;
+ uint32_t agg_id;
if (unlikely(rxq->in_reset)) {
PMD_DRV_LOG_LINE(ERR, "rxq->in_reset: raw_cp_cons:%d",
*raw_cp_cons);
- bnxt_discard_rx(rxq->bp, cpr, raw_cp_cons, tpa_end);
+ bnxt_discard_rx(bp, cpr, raw_cp_cons, tpa_end);
return NULL;
}
- if (BNXT_CHIP_P5_P7(rxq->bp)) {
+ if (BNXT_CHIP_P5_P7(bp)) {
struct rx_tpa_v2_end_cmpl *th_tpa_end;
struct rx_tpa_v2_end_cmpl_hi *th_tpa_end1;
@@ -442,6 +450,15 @@ static inline struct rte_mbuf *bnxt_tpa_end(
payload_offset = tpa_end->payload_offset;
}
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA end: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_discard_rx(bp, cpr, raw_cp_cons, tpa_end);
+ bnxt_sched_ring_reset(rxq);
+ return NULL;
+ }
+
tpa_info = &rxr->tpa_info[agg_id];
mbuf = tpa_info->mbuf;
RTE_ASSERT(mbuf != NULL);
@@ -1126,9 +1143,18 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt,
if (cmp_type == RX_TPA_V2_ABUF_CMPL_TYPE_RX_TPA_AGG) {
struct rx_tpa_v2_abuf_cmpl *rx_agg = (void *)rxcmp;
- uint16_t agg_id = rte_cpu_to_le_16(rx_agg->agg_id);
+ uint32_t agg_id = rte_le_to_cpu_16(rx_agg->agg_id);
struct bnxt_tpa_info *tpa_info;
+ if (unlikely(agg_id >= BNXT_TPA_MAX_AGGS(bp))) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA abuf: invalid agg_id %u (max %u)",
+ agg_id, BNXT_TPA_MAX_AGGS(bp));
+ bnxt_sched_ring_reset(rxq);
+ rc = -EINVAL;
+ goto next_rx;
+ }
+
tpa_info = &rxr->tpa_info[agg_id];
RTE_ASSERT(tpa_info->agg_count < 16);
tpa_info->agg_arr[tpa_info->agg_count++] = *rx_agg;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 3/5] net/bnxt: harden sprintf bounds for device memory names
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 2/5] net/bnxt: validate TPA aggregation ID from completions Mohammad Shuab Siddique
@ 2026-09-29 0:24 ` Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 4/5] net/bnxt: fix bounds in MAC address pool index Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-29 0:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Keegan Freyhof, stable,
Mohammad Shuab Siddique
From: Keegan Freyhof <keegan.freyhof@broadcom.com>
sprintf() into fixed-size stack buffers such as
char type[RTE_MEMZONE_NAMESIZE] does not bound the write to the
buffer. bnxt_hwrm_ver_get()'s "bnxt_hwrm_short_" PCI_PRI_FMT label
overflows a 32-byte RTE_MEMZONE_NAMESIZE buffer once the PCI domain
needs more than 4 hex digits: rte_pci_addr.domain is a uint32_t, and
PCI_PRI_FMT's %.4x is a minimum width, not a maximum, so an 8-digit
domain plus the 16-character prefix plus the rest of the PCI address
string plus the terminating NUL is 33 bytes into 32.
Convert this and the other sprintf() calls building memzone/malloc
names and HWRM CFA pair_name request fields to snprintf(), which
bounds the write and truncates instead of overflowing. The return
value is not checked: none of these format strings involve locale or
multibyte conversion, so a negative return is not reachable, and a
truncated debug label or pair_name is not itself a memory-safety
concern -- a truncated pair_name simply fails to match at the
firmware side, handled the same way as any other not-found pair.
Also write the per-flow xstat names directly into
xstats_names[count].name via snprintf() instead of through an
intermediate buf plus strlcpy(), since the destination is already
exactly sized for that format string.
Fixes: 79cc1efd99c6 ("net/bnxt: support extended HWRM request sizes")
Cc: stable@dpdk.org
Signed-off-by: Keegan Freyhof <keegan.freyhof@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
v3:
* Dropped check_snprintf_rc() and the early-return paths on the CFA
pair_name sites entirely -- Stephen Hemminger noted the rc < 0
branch is unreachable and plain snprintf() is enough for the PCI
domain overflow this patch actually targets. All ten snprintf()
sites now behave the same way: bounded, unchecked, truncate on
overflow. This also removes the three bugs (a leak, a stale flag,
and missing HWRM_UNLOCK()s) v2's early-return paths had introduced
and fixed, since there is no early-return path left to have them.
drivers/net/bnxt/bnxt.h | 1 +
drivers/net/bnxt/bnxt_ethdev.c | 14 +++++++-------
drivers/net/bnxt/bnxt_hwrm.c | 10 +++++-----
drivers/net/bnxt/bnxt_stats.c | 15 ++++++---------
4 files changed, 19 insertions(+), 21 deletions(-)
diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h
index 336de75da0..f3edfb9530 100644
--- a/drivers/net/bnxt/bnxt.h
+++ b/drivers/net/bnxt/bnxt.h
@@ -1285,6 +1285,7 @@ extern int bnxt_logtype_driver;
BNXT_LINK_SPEEDS_V2_VF((bp))))
#define BNXT_MAX_SPEED_LANES 8
#define BNXT_SUPPORTS_TPA(bp) (!BNXT_CHIP_P5_P7(bp) || (bp)->max_tpa_v2)
+
extern const struct rte_flow_ops bnxt_ulp_rte_flow_ops;
int32_t bnxt_ulp_port_init(struct bnxt *bp);
void bnxt_ulp_port_deinit(struct bnxt *bp);
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 4d4349457c..11e8f7908d 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -647,12 +647,12 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
{
struct rte_pci_device *pdev = bp->pdev;
char type[RTE_MEMZONE_NAMESIZE];
- uint16_t max_fc;
int rc = 0;
+ uint16_t max_fc;
max_fc = bp->flow_stat->max_fc;
- sprintf(type, "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+ snprintf(type, sizeof(type), "bnxt_rx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
/* 4 bytes for each counter-id */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
@@ -661,7 +661,7 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+ snprintf(type, sizeof(type), "bnxt_rx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
/* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
@@ -670,7 +670,7 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
+ snprintf(type, sizeof(type), "bnxt_tx_fc_in_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
/* 4 bytes for each counter-id */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
@@ -679,7 +679,7 @@ static int bnxt_init_fc_ctx_mem(struct bnxt *bp)
if (rc)
return rc;
- sprintf(type, "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
+ snprintf(type, sizeof(type), "bnxt_tx_fc_out_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
/* 16 bytes for each counter - 8 bytes pkt_count, 8 bytes byte_count */
rc = bnxt_alloc_ctx_mem_buf(bp, type,
@@ -5232,8 +5232,8 @@ int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp)
{
struct bnxt_ctx_mem_info *ctx = bp->ctx;
struct bnxt_ctx_mem *ctx2;
- uint16_t type;
int rc = 0;
+ uint16_t type;
ctx2 = &ctx->ctx_arr[0];
for (type = 0; type < ctx->types && rc == 0; type++) {
@@ -5254,7 +5254,7 @@ int bnxt_alloc_ctx_pg_tbls(struct bnxt *bp)
for (i = 0; i < w && rc == 0; i++) {
char name[RTE_MEMZONE_NAMESIZE] = {0};
- sprintf(name, "_%d_%d", i, type);
+ snprintf(name, sizeof(name), "_%d_%d", i, type);
if (ctxm->entry_multiple)
entries = bnxt_roundup(ctxm->max_entries,
diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 1615b36aae..361402b36f 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -1583,12 +1583,12 @@ int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp)
int bnxt_hwrm_ver_get(struct bnxt *bp, uint32_t timeout)
{
- int rc = 0;
struct hwrm_ver_get_input req = {.req_type = 0 };
struct hwrm_ver_get_output *resp = bp->hwrm_cmd_resp_addr;
uint32_t fw_version;
uint16_t max_resp_len;
char type[RTE_MEMZONE_NAMESIZE];
+ int rc = 0;
uint32_t dev_caps_cfg;
bp->max_req_len = HWRM_MAX_REQ_LEN;
@@ -1669,10 +1669,9 @@ int bnxt_hwrm_ver_get(struct bnxt *bp, uint32_t timeout)
(dev_caps_cfg &
HWRM_VER_GET_OUTPUT_DEV_CAPS_CFG_SHORT_CMD_REQUIRED)) ||
bp->hwrm_max_ext_req_len > HWRM_MAX_REQ_LEN) {
- sprintf(type, "bnxt_hwrm_short_" PCI_PRI_FMT,
+ snprintf(type, sizeof(type), "bnxt_hwrm_short_" PCI_PRI_FMT,
bp->pdev->addr.domain, bp->pdev->addr.bus,
bp->pdev->addr.devid, bp->pdev->addr.function);
-
rte_free(bp->hwrm_short_cmd_req_addr);
bp->hwrm_short_cmd_req_addr =
@@ -3542,7 +3541,7 @@ int bnxt_alloc_hwrm_resources(struct bnxt *bp)
struct rte_pci_device *pdev = bp->pdev;
char type[RTE_MEMZONE_NAMESIZE];
- sprintf(type, "bnxt_hwrm_" PCI_PRI_FMT, pdev->addr.domain,
+ snprintf(type, sizeof(type), "bnxt_hwrm_" PCI_PRI_FMT, pdev->addr.domain,
pdev->addr.bus, pdev->addr.devid, pdev->addr.function);
bp->max_resp_len = BNXT_PAGE_SIZE;
bp->hwrm_cmd_resp_addr = rte_malloc(type, bp->max_resp_len, 0);
@@ -6792,7 +6791,7 @@ static int bnxt_alloc_all_ctx_pg_info(struct bnxt *bp)
if (ctxm->instance_bmap)
n = hweight32(ctxm->instance_bmap);
- sprintf(name, "bnxt_ctx_pgmem_%d_%d",
+ snprintf(name, sizeof(name), "bnxt_ctx_pgmem_%d_%d",
bp->eth_dev->data->port_id, type);
ctxm->pg_info = rte_malloc(name, sizeof(*ctxm->pg_info) * n,
RTE_CACHE_LINE_SIZE);
@@ -7836,6 +7835,7 @@ int bnxt_hwrm_cfa_pair_free(struct bnxt *bp, struct bnxt_representor *rep_bp)
HWRM_PREP(&req, HWRM_CFA_PAIR_FREE, BNXT_USE_CHIMP_MB);
snprintf(req.pair_name, sizeof(req.pair_name), "%svfr%d",
bp->eth_dev->data->name, rep_bp->vf_id);
+
req.pf_b_id = rep_bp->parent_pf_idx;
req.pair_mode = HWRM_CFA_PAIR_FREE_INPUT_PAIR_MODE_REP2FN_TRUFLOW;
req.vf_id = BNXT_REP_PF(rep_bp) ? rte_cpu_to_le_16(((uint16_t)-1)) :
diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index 4074613eb0..05e8944f47 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -1165,17 +1165,14 @@ int bnxt_dev_xstats_get_names_op(struct rte_eth_dev *eth_dev,
bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_MGMT &&
BNXT_FLOW_XSTATS_EN(bp)) {
for (i = 0; i < bp->max_l2_ctx; i++) {
- char buf[RTE_ETH_XSTATS_NAME_SIZE];
-
- sprintf(buf, "flow_%d_bytes", i);
- strlcpy(xstats_names[count].name, buf,
- sizeof(xstats_names[count].name));
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "flow_%d_bytes", i);
count++;
- sprintf(buf, "flow_%d_packets", i);
- strlcpy(xstats_names[count].name, buf,
- sizeof(xstats_names[count].name));
-
+ snprintf(xstats_names[count].name,
+ sizeof(xstats_names[count].name),
+ "flow_%d_packets", i);
count++;
}
}
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 4/5] net/bnxt: fix bounds in MAC address pool index
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (2 preceding siblings ...)
2026-09-29 0:24 ` [PATCH v3 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
@ 2026-09-29 0:24 ` Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-29 0:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, Chenna Arnoori, stable,
Mohammad Shuab Siddique
From: Chenna Arnoori <chenna.arnoori@broadcom.com>
bnxt_mac_addr_add_op() indexed bp->vnic_info[pool] with a
caller-supplied pool before validating it against bp->max_vnics, and
before checking bp->vnic_info was even allocated yet (it is NULL
until the port is started). The existing "if (!vnic)" check was
always false, since vnic held the address of an array element and
is never NULL. bp->max_vnics is known from probe onward, so the pool
bound is checked first and unconditionally; the dev_started and
vnic_info checks, which gate whether there is anything to index yet,
follow it.
Fixes: 51fafb89a9a0 ("net/bnxt: get rid of ff pools and use VNIC info array")
Cc: stable@dpdk.org
Signed-off-by: Chenna Arnoori <chenna.arnoori@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
v3:
* Retitled from "fix bounds in MAC pool index and flow parsing" and
dropped the flow-parsing half entirely (the bounded VOID-item skip
in bnxt_flow_non_void_item()/bnxt_flow_non_void_action()) --
Stephen Hemminger pointed out rte_flow patterns/actions are always
END-terminated by API contract, so that bound did not guard a
reachable path; reverted to the original unbounded skip loop
rather than keep unnecessary defensive code. Dropped the
corresponding Fixes: 5c1171c97216 tag.
* Reordered the remaining MAC-pool fix so the pool-vs-max_vnics bound
check runs before the dev_started/vnic_info checks, not after --
also per Stephen Hemminger.
drivers/net/bnxt/bnxt_ethdev.c | 11 ++++++++---
drivers/net/bnxt/bnxt_flow.c | 1 +
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 11e8f7908d..20084826d3 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -2105,7 +2105,7 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
uint32_t index, uint32_t pool)
{
struct bnxt *bp = eth_dev->data->dev_private;
- struct bnxt_vnic_info *vnic = &bp->vnic_info[pool];
+ struct bnxt_vnic_info *vnic;
int rc = 0;
rc = is_bnxt_in_error(bp);
@@ -2117,8 +2117,8 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
return -ENOTSUP;
}
- if (!vnic) {
- PMD_DRV_LOG_LINE(ERR, "VNIC not found for pool %d!", pool);
+ if (pool >= bp->max_vnics) {
+ PMD_DRV_LOG_LINE(ERR, "Pool %u exceeds VNIC count %u!", pool, bp->max_vnics);
return -EINVAL;
}
@@ -2126,6 +2126,11 @@ static int bnxt_mac_addr_add_op(struct rte_eth_dev *eth_dev,
if (!eth_dev->data->dev_started)
return 0;
+ if (bp->vnic_info == NULL)
+ return 0;
+
+ vnic = &bp->vnic_info[pool];
+
rc = bnxt_add_mac_filter(bp, vnic, mac_addr, index, pool);
return rc;
diff --git a/drivers/net/bnxt/bnxt_flow.c b/drivers/net/bnxt/bnxt_flow.c
index 4bf38043b5..7b27d62697 100644
--- a/drivers/net/bnxt/bnxt_flow.c
+++ b/drivers/net/bnxt/bnxt_flow.c
@@ -1697,6 +1697,7 @@ bnxt_validate_and_parse_flow(struct rte_eth_dev *dev,
while (act->type != RTE_FLOW_ACTION_TYPE_END)
goto start;
+
return rc;
ret:
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH v3 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
` (3 preceding siblings ...)
2026-09-29 0:24 ` [PATCH v3 4/5] net/bnxt: fix bounds in MAC address pool index Mohammad Shuab Siddique
@ 2026-09-29 0:24 ` Mohammad Shuab Siddique
4 siblings, 0 replies; 20+ messages in thread
From: Mohammad Shuab Siddique @ 2026-09-29 0:24 UTC (permalink / raw)
To: dev; +Cc: kishore.padmanabha, stable, Mohammad Shuab Siddique
From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Three independent out-of-bounds issues:
- bnxt_rx_pkt() incremented tpa_info->agg_count and indexed
tpa_info->agg_arr[] with only an RTE_ASSERT (compiled out in release
builds) guarding the array bound, allowing an out-of-bounds write if
firmware sent more aggregation segments than TPA_MAX_NUM_SEGS.
- bnxt_rx_descriptor_status_op() used the firmware-supplied completion
opaque value directly as an rx_buf_ring[] index without masking it to
the ring size first.
- bnxt_hwrm_func_vf_vnic_query() returned the firmware-reported
vnic_id_cnt unclamped; a value exceeding bp->pf->total_vnics would
cause the caller to iterate past the end of its VNIC ID buffer.
Fixes: b150a7e7ee66 ("net/bnxt: support LRO on Thor adapters")
Fixes: 0fe613bb87b2 ("net/bnxt: support Rx descriptor status")
Fixes: cbcd375d37d2 ("net/bnxt: fix HWRM macros and locking")
Cc: stable@dpdk.org
Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique@broadcom.com>
---
drivers/net/bnxt/bnxt_ethdev.c | 3 ++-
drivers/net/bnxt/bnxt_hwrm.c | 3 ++-
drivers/net/bnxt/bnxt_rxr.c | 10 +++++++++-
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 20084826d3..3a530c31aa 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -3624,7 +3624,8 @@ bnxt_rx_descriptor_status_op(void *rx_queue, uint16_t offset)
case CMPL_BASE_TYPE_RX_L2:
case CMPL_BASE_TYPE_RX_L2_V2:
if (desc == offset) {
- cons = rxcmp->opaque;
+ cons = RING_IDX(rxr->rx_ring_struct,
+ rxcmp->opaque);
if (rxr->rx_buf_ring[cons])
return RTE_ETH_RX_DESC_DONE;
else
diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 361402b36f..42ed6e5ae1 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -6234,7 +6234,8 @@ static int bnxt_hwrm_func_vf_vnic_query(struct bnxt *bp, uint16_t vf,
}
rc = bnxt_hwrm_send_message(bp, &req, sizeof(req), BNXT_USE_CHIMP_MB);
HWRM_CHECK_RESULT();
- rc = rte_le_to_cpu_32(resp->vnic_id_cnt);
+ rc = RTE_MIN(rte_le_to_cpu_32(resp->vnic_id_cnt),
+ (uint32_t)bp->pf->total_vnics);
HWRM_UNLOCK();
diff --git a/drivers/net/bnxt/bnxt_rxr.c b/drivers/net/bnxt/bnxt_rxr.c
index 1790ce839f..fa10446c27 100644
--- a/drivers/net/bnxt/bnxt_rxr.c
+++ b/drivers/net/bnxt/bnxt_rxr.c
@@ -1156,7 +1156,15 @@ static int bnxt_rx_pkt(struct rte_mbuf **rx_pkt,
}
tpa_info = &rxr->tpa_info[agg_id];
- RTE_ASSERT(tpa_info->agg_count < 16);
+ if (unlikely(tpa_info->agg_count >= TPA_MAX_NUM_SEGS)) {
+ PMD_DRV_LOG_LINE(ERR,
+ "TPA abuf: agg_count %u exceeds max %u",
+ tpa_info->agg_count, TPA_MAX_NUM_SEGS);
+ tpa_info->agg_count = 0;
+ bnxt_sched_ring_reset(rxq);
+ rc = -EINVAL;
+ goto next_rx;
+ }
tpa_info->agg_arr[tpa_info->agg_count++] = *rx_agg;
rc = -EINVAL; /* Continue w/o new mbuf */
goto next_rx;
--
2.47.3
^ permalink raw reply related [flat|nested] 20+ messages in thread
end of thread, other threads:[~2026-09-29 0:22 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-18 3:27 [PATCH 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
2026-09-18 3:27 ` [PATCH 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 2/5] net/bnxt: fix bounds on TPA aggregation ID from completions Mohammad Shuab Siddique
2026-09-21 2:24 ` [PATCH v2 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
2026-09-21 15:49 ` Stephen Hemminger
2026-09-21 2:24 ` [PATCH v2 4/5] net/bnxt: fix bounds in MAC pool index and flow parsing Mohammad Shuab Siddique
2026-09-21 15:50 ` Stephen Hemminger
2026-09-21 2:24 ` [PATCH v2 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 0/5] net/bnxt: fix flow, Rx and naming bounds issues Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 1/5] net/bnxt: fix stack exhaustion in flow stats Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 2/5] net/bnxt: validate TPA aggregation ID from completions Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 3/5] net/bnxt: harden sprintf bounds for device memory names Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 4/5] net/bnxt: fix bounds in MAC address pool index Mohammad Shuab Siddique
2026-09-29 0:24 ` [PATCH v3 5/5] net/bnxt: fix TPA agg Rx descriptor and VNIC query bounds Mohammad Shuab Siddique
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox