[PATCH net 08/12] net: systemport: Fix out-of-bounds array accesses in DSA queue mapping

From: Florian Fainelli

Date: Mon Sep 21 2026 - 19:23:30 EST


The priv->ring_map array has a fixed size of (DSA_MAX_PORTS * 8). In
bcm_sysport_select_queue(), bcm_sysport_map_queues(), and
bcm_sysport_unmap_queues(), indices calculated as
(qp + port * num_tx_queues) were accessed without checking against
ARRAY_SIZE(priv->ring_map). If unusual port or queue configurations are
encountered, this could lead to out-of-bounds array accesses.

Additionally, on SYSTEMPORT Lite, netif_set_real_num_tx_queues() was
called with slave_dev->num_tx_queues / 2, which could evaluate to 0 if
slave_dev->num_tx_queues is 1, causing netif_set_real_num_tx_queues() to
fail with -EINVAL.

Fix these by clamping the real number of queues to at least 1 and adding
bounds checks on priv->ring_map.

Fixes: d156576362c0 ("net: systemport: Establish lower/upper queue mapping")
Assisted-by: LLM
Signed-off-by: Florian Fainelli <florian.fainelli@xxxxxxxxxxxx>
---
drivers/net/ethernet/broadcom/bcmsysport.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index 95cead1df160..130545cce045 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -2273,7 +2273,7 @@ static u16 bcm_sysport_select_queue(struct net_device *dev, struct sk_buff *skb,
struct bcm_sysport_priv *priv = netdev_priv(dev);
u16 queue = skb_get_queue_mapping(skb);
struct bcm_sysport_tx_ring *tx_ring;
- unsigned int q, port;
+ unsigned int q, port, index;

if (!netdev_uses_dsa(dev))
return netdev_pick_tx(dev, skb, NULL);
@@ -2281,8 +2281,11 @@ static u16 bcm_sysport_select_queue(struct net_device *dev, struct sk_buff *skb,
/* DSA tagging layer will have configured the correct queue */
q = BRCM_TAG_GET_QUEUE(queue);
port = BRCM_TAG_GET_PORT(queue);
- tx_ring = priv->ring_map[q + port * priv->per_port_num_tx_queues];
+ index = q + port * priv->per_port_num_tx_queues;
+ if (unlikely(index >= ARRAY_SIZE(priv->ring_map)))
+ return netdev_pick_tx(dev, skb, NULL);

+ tx_ring = priv->ring_map[index];
if (unlikely(!tx_ring))
return netdev_pick_tx(dev, skb, NULL);

@@ -2329,7 +2332,8 @@ static int bcm_sysport_map_queues(struct net_device *dev,
*/
if (priv->is_lite)
netif_set_real_num_tx_queues(slave_dev,
- slave_dev->num_tx_queues / 2);
+ max_t(unsigned int, 1,
+ slave_dev->num_tx_queues / 2));

num_tx_queues = slave_dev->real_num_tx_queues;

@@ -2352,7 +2356,8 @@ static int bcm_sysport_map_queues(struct net_device *dev,
ring->switch_queue = qp;
ring->switch_port = port;
ring->inspect = true;
- priv->ring_map[qp + port * num_tx_queues] = ring;
+ if (qp + port * num_tx_queues < ARRAY_SIZE(priv->ring_map))
+ priv->ring_map[qp + port * num_tx_queues] = ring;
qp++;
}

@@ -2383,7 +2388,8 @@ static int bcm_sysport_unmap_queues(struct net_device *dev,

ring->inspect = false;
qp = ring->switch_queue;
- priv->ring_map[qp + port * num_tx_queues] = NULL;
+ if (qp + port * num_tx_queues < ARRAY_SIZE(priv->ring_map))
+ priv->ring_map[qp + port * num_tx_queues] = NULL;
}

return 0;
--
2.34.1