[PATCH v2 14/17] net/dpaa2: fix MAC stats DMA buffer allocation per xstats call

Maxime Leroy
2026-02-26T14:36:05Z

dpaa2_dev_mac_setup_stats() allocates and frees DMA buffers on every
xstats_get() call. This is wasteful and not thread-safe: concurrent
callers can overwrite priv pointers, leading to use-after-free. It
also does not check for allocation failure before passing IOVAs to
the MC firmware.

Move the DMA buffer allocation to dpaa2_dev_init() (only when MC
version supports MAC stats) and free them in dpaa2_dev_close(). In
xstats_get(), just check if the buffers were allocated.

Not tested, found by code review.

Fixes: d1cdef2ab5 ("net/dpaa2: add dpmac counters in xstats")
Cc: stable@dpdk.org

Reported-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: Maxime Leroy <maxime@leroys.fr>
---
drivers/net/dpaa2/dpaa2_ethdev.c | 65 +++++++++++++++-----------------
1 file changed, 30 insertions(+), 35 deletions(-)

diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index 3875164794..d5e30ce5fb 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -1550,6 +1550,11 @@ dpaa2_dev_close(struct rte_eth_dev *dev)

rte_free(priv->extract.qos_extract_param);

+ rte_free(priv->cnt_idx_dma_mem);
+ rte_free(priv->cnt_values_dma_mem);
+ priv->cnt_idx_dma_mem = NULL;
+ priv->cnt_values_dma_mem = NULL;
+
DPAA2_PMD_INFO("%s: netdev deleted", dev->data->name);
return 0;
}
@@ -1905,7 +1910,6 @@ dpaa2_dev_xstats_get(struct rte_eth_dev *dev,
unsigned int i = 0, j = 0, num = RTE_DIM(dpaa2_xstats_strings);
struct dpaa2_dev_priv *priv = dev->data->dev_private;
union dpni_statistics value[13] = {};
- struct mc_version mc_ver_info = {0};
struct dpni_rx_tc_policing_cfg cfg;
uint8_t page_id, stats_id;
uint64_t *cnt_values;
@@ -1976,44 +1980,24 @@ dpaa2_dev_xstats_get(struct rte_eth_dev *dev,
i++;
}

- if (mc_get_version(dpni, CMD_PRI_LOW, &mc_ver_info))
- DPAA2_PMD_WARN("Unable to obtain MC version");
-
- /* mac_statistics supported on MC version > 10.39.0 */
- if (mc_ver_info.major >= MC_VER_MAJOR &&
- mc_ver_info.minor >= MC_VER_MINOR &&
- mc_ver_info.revision > 0) {
- dpaa2_dev_mac_setup_stats(dev);
- retcode = dpni_get_mac_statistics(dpni, CMD_PRI_LOW, priv->token,
- priv->cnt_idx_iova,
- priv->cnt_values_iova,
- DPAA2_MAC_NUM_STATS);
- if (retcode) {
- while (i >= (num - DPAA2_MAC_NUM_STATS) && i < num) {
- xstats[i].id = i;
- xstats[i].value = 0;
- i++;
- }
- }
- if (!retcode) {
- cnt_values = priv->cnt_values_dma_mem;
- while (i >= (num - DPAA2_MAC_NUM_STATS) && i < num) {
- /* mac counters value */
- xstats[i].id = i;
- xstats[i].value = rte_le_to_cpu_64(*cnt_values++);
- i++;
- }
- }
- rte_free(priv->cnt_values_dma_mem);
- rte_free(priv->cnt_idx_dma_mem);
- priv->cnt_idx_dma_mem = NULL;
- priv->cnt_values_dma_mem = NULL;
- } else {
+ if (priv->cnt_idx_dma_mem &&
+ !dpni_get_mac_statistics(dpni, CMD_PRI_LOW, priv->token,
+ priv->cnt_idx_iova,
+ priv->cnt_values_iova,
+ DPAA2_MAC_NUM_STATS)) {
+ cnt_values = priv->cnt_values_dma_mem;
while (i >= (num - DPAA2_MAC_NUM_STATS) && i < num) {
xstats[i].id = i;
- xstats[i].value = 0;
+ xstats[i].value = rte_le_to_cpu_64(*cnt_values++);
i++;
}
+ return i;
+ }
+
+ while (i >= (num - DPAA2_MAC_NUM_STATS) && i < num) {
+ xstats[i].id = i;
+ xstats[i].value = 0;
+ i++;
}

return i;
@@ -3155,6 +3139,17 @@ dpaa2_dev_init(struct rte_eth_dev *eth_dev)

priv->speed_capa = dpaa2_dev_get_speed_capability(eth_dev);

+ /* mac_statistics supported on MC version > 10.39.0 */
+ {
+ struct mc_version mc_ver_info = {0};
+
+ if (!mc_get_version(dpni_dev, CMD_PRI_LOW, &mc_ver_info) &&
+ mc_ver_info.major >= MC_VER_MAJOR &&
+ mc_ver_info.minor >= MC_VER_MINOR &&
+ mc_ver_info.revision > 0)
+ dpaa2_dev_mac_setup_stats(eth_dev);
+ }
+
return 0;
init_err:
dpaa2_dev_close(eth_dev);
--
2.43.0