DORMANTno replies

[PATCH net v2] net: prestera: validate num_counters in counter response

From: Aamir Ahmed <hidden>
Date: 2026-09-14 19:24:07
Also in: lkml
Subsystem: marvell prestera ethernet switch driver, networking drivers, the rest · Maintainers: Elad Nachman, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

prestera_hw_counters_get() trusts the counter count in the firmware
reply, using it to walk resp->stats[], sized for the requested count,
and to write into the caller's stats array. A malformed reply that
claims more counters than either holds reads past the response buffer
and writes past the array.

The array is sized by the block's counter count, which can be smaller
than the fixed bulk request, and the only caller passes a pointer into
the middle of it, so the helper cannot bound the writes without being
told how much space is left.

Pass the remaining capacity down and reject a reply that exceeds the
request or the space left. This also keeps counter->total_read within
block->num_counters, so the next poll cannot start past the array.

Fixes: 6e36c7bcb461 ("net: prestera: add counter HW API")
Assisted-by: LLM
Signed-off-by: Aamir Ahmed <redacted>
---
v2:
  - also bound the reply by the space left in the caller's stats array;
    v1 bounded it only by the requested count, which is fixed at 256 and
    can exceed the array, so a block with fewer counters could still be
    overrun (Sashiko)
  - add the Assisted-by: LLM tag
  - name the target tree in the subject
  - Cc LKML
v1: https://lore.kernel.org/netdev/AS8P251MB0001CC8A4737B0CC46F41DDFC8B22@AS8P251MB0001.EURP251.PROD.OUTLOOK.COM/ (local)

The request itself is left at COUNTER_BULK_SIZE so the firmware sees no
change; clamping it to the space left would also work, if preferred.

Built with W=1 (prestera_hw.o, prestera_counter.o) on x86_64; no
warnings. I have no Prestera hardware, so it is not runtime-tested.

 drivers/net/ethernet/marvell/prestera/prestera_counter.c | 5 ++++-
 drivers/net/ethernet/marvell/prestera/prestera_hw.c      | 8 +++++++-
 drivers/net/ethernet/marvell/prestera/prestera_hw.h      | 3 ++-
 3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_counter.c b/drivers/net/ethernet/marvell/prestera/prestera_counter.c
index 3a762d17ba6c..f261104729e9 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_counter.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_counter.c
@@ -342,6 +342,7 @@ static void prestera_counter_stats_work(struct work_struct *work)
 	u32 resched_time = COUNTER_POLL_TIME;
 	u32 count = COUNTER_BULK_SIZE;
 	bool done = false;
+	u32 remaining;
 	int err;
 	u32 i;
 
@@ -368,10 +369,12 @@ static void prestera_counter_stats_work(struct work_struct *work)
 		goto resched;
 	}
 
+	remaining = block->num_counters - counter->total_read;
 	prestera_counter_block_lock(block);
 	err = prestera_hw_counters_get(counter->sw, counter->total_read,
 				       &count, &done,
-				       &block->stats[counter->total_read]);
+				       &block->stats[counter->total_read],
+				       remaining);
 	prestera_counter_block_unlock(block);
 	if (err)
 		goto abort;
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.c b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
index 7695cbb2ce62..2e5cffefea70 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_hw.c
+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.c
@@ -2305,7 +2305,8 @@ int prestera_hw_counter_abort(struct prestera_switch *sw)
 
 int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx,
 			     u32 *len, bool *done,
-			     struct prestera_counter_stats *stats)
+			     struct prestera_counter_stats *stats,
+			     u32 stats_len)
 {
 	struct prestera_msg_counter_resp *resp;
 	struct prestera_msg_counter_req req = {
@@ -2324,6 +2325,11 @@ int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx,
 	if (err)
 		goto free_buff;
 
+	if (__le32_to_cpu(resp->num_counters) > min(*len, stats_len)) {
+		err = -EINVAL;
+		goto free_buff;
+	}
+
 	for (i = 0; i < __le32_to_cpu(resp->num_counters); i++) {
 		stats[i].packets += __le64_to_cpu(resp->stats[i].packets);
 		stats[i].bytes += __le64_to_cpu(resp->stats[i].bytes);
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_hw.h b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
index 0a929279e1ce..2e9aceb7a136 100644
--- a/drivers/net/ethernet/marvell/prestera/prestera_hw.h
+++ b/drivers/net/ethernet/marvell/prestera/prestera_hw.h
@@ -235,7 +235,8 @@ int prestera_hw_counter_trigger(struct prestera_switch *sw, u32 block_id);
 int prestera_hw_counter_abort(struct prestera_switch *sw);
 int prestera_hw_counters_get(struct prestera_switch *sw, u32 idx,
 			     u32 *len, bool *done,
-			     struct prestera_counter_stats *stats);
+			     struct prestera_counter_stats *stats,
+			     u32 stats_len);
 int prestera_hw_counter_block_get(struct prestera_switch *sw,
 				  u32 client, u32 *block_id, u32 *offset,
 				  u32 *num_counters);
base-commit: c297ed90fbba72d32b7759aae362b36d15b2db1f
-- 
2.43.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help