[PATCH] qede: validate TPA aggregation indices from CQEs
From: Pengpeng Hou
Date: Mon Mar 23 2026 - 03:28:03 EST
The fast-path TPA handlers index rxq->tpa_info[] directly with the
completion-provided tpa_agg_index field. That field is only a raw u8 in
the CQE layout, while rxq->tpa_info has ETH_TPA_MAX_AGGS_NUM entries.
Reject out-of-range indices before touching rxq->tpa_info[] and recycle
the affected receive BDs instead of indexing past the fixed aggregation
state array.
Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>
---
drivers/net/ethernet/qlogic/qede/qede_fp.c | 59 ++++++++++++++++++++--
1 file changed, 54 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c
index e338bfc8b7b2..85d640de5f21 100644
--- a/drivers/net/ethernet/qlogic/qede/qede_fp.c
+++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c
@@ -668,8 +668,18 @@ static int qede_fill_frag_skb(struct qede_dev *edev,
{
struct sw_rx_data *current_bd = &rxq->sw_rx_ring[rxq->sw_rx_cons &
NUM_RX_BDS_MAX];
- struct qede_agg_info *tpa_info = &rxq->tpa_info[tpa_agg_index];
- struct sk_buff *skb = tpa_info->skb;
+ struct qede_agg_info *tpa_info;
+ struct sk_buff *skb;
+
+ if (unlikely(tpa_agg_index >= ARRAY_SIZE(rxq->tpa_info))) {
+ DP_NOTICE(edev, "TPA aggregation index %u out of range\n",
+ tpa_agg_index);
+ qede_recycle_rx_bd_ring(rxq, 1);
+ return -EINVAL;
+ }
+
+ tpa_info = &rxq->tpa_info[tpa_agg_index];
+ skb = tpa_info->skb;
if (unlikely(tpa_info->state != QEDE_AGG_STATE_START))
goto out;
@@ -833,10 +843,26 @@ static void qede_tpa_start(struct qede_dev *edev,
struct qede_rx_queue *rxq,
struct eth_fast_path_rx_tpa_start_cqe *cqe)
{
- struct qede_agg_info *tpa_info = &rxq->tpa_info[cqe->tpa_agg_index];
+ struct qede_agg_info *tpa_info;
struct sw_rx_data *sw_rx_data_cons;
+ u8 agg_index = cqe->tpa_agg_index;
+ u8 num_bds = 1;
u16 pad;
+ if (cqe->bw_ext_bd_len_list[0])
+ num_bds++;
+ if (cqe->bw_ext_bd_len_list[1])
+ num_bds++;
+
+ if (unlikely(agg_index >= ARRAY_SIZE(rxq->tpa_info))) {
+ DP_NOTICE(edev, "TPA aggregation index %u out of range\n",
+ agg_index);
+ qede_recycle_rx_bd_ring(rxq, num_bds);
+ return;
+ }
+
+ tpa_info = &rxq->tpa_info[agg_index];
+
sw_rx_data_cons = &rxq->sw_rx_ring[rxq->sw_rx_cons & NUM_RX_BDS_MAX];
pad = cqe->placement_offset + rxq->rx_headroom;
@@ -876,7 +902,7 @@ static void qede_tpa_start(struct qede_dev *edev,
cons_buf: /* We still need to handle bd_len_list to consume buffers */
if (likely(cqe->bw_ext_bd_len_list[0]))
- qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
+ qede_fill_frag_skb(edev, rxq, agg_index,
le16_to_cpu(cqe->bw_ext_bd_len_list[0]));
if (unlikely(cqe->bw_ext_bd_len_list[1])) {
@@ -960,9 +986,21 @@ static inline void qede_tpa_cont(struct qede_dev *edev,
struct eth_fast_path_rx_tpa_cont_cqe *cqe)
{
int i;
+ u8 agg_index = cqe->tpa_agg_index;
+
+ if (unlikely(agg_index >= ARRAY_SIZE(rxq->tpa_info))) {
+ DP_NOTICE(edev, "TPA aggregation index %u out of range\n",
+ agg_index);
+
+ for (i = 0; cqe->len_list[i] &&
+ i < ARRAY_SIZE(cqe->len_list); i++)
+ qede_recycle_rx_bd_ring(rxq, 1);
+
+ return;
+ }
for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++)
- qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index,
+ qede_fill_frag_skb(edev, rxq, agg_index,
le16_to_cpu(cqe->len_list[i]));
if (unlikely(i > 1))
@@ -979,6 +1017,17 @@ static int qede_tpa_end(struct qede_dev *edev,
struct sk_buff *skb;
int i;
+ if (unlikely(cqe->tpa_agg_index >= ARRAY_SIZE(rxq->tpa_info))) {
+ DP_NOTICE(edev, "TPA aggregation index %u out of range\n",
+ cqe->tpa_agg_index);
+
+ for (i = 0; cqe->len_list[i] &&
+ i < ARRAY_SIZE(cqe->len_list); i++)
+ qede_recycle_rx_bd_ring(rxq, 1);
+
+ return 0;
+ }
+
tpa_info = &rxq->tpa_info[cqe->tpa_agg_index];
skb = tpa_info->skb;
--
2.50.1 (Apple Git-155)