[PATCH net v2] net: prestera: validate num_counters in counter response
flat view
DORMANTno replies
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