]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: ifb: report ethtool stats over num_tx_queues
authorMichael Bommarito <michael.bommarito@gmail.com>
Thu, 14 May 2026 01:37:39 +0000 (21:37 -0400)
committerJakub Kicinski <kuba@kernel.org>
Fri, 15 May 2026 01:40:04 +0000 (18:40 -0700)
ifb_dev_init() allocates dp->tx_private to dev->num_tx_queues
entries via kzalloc_objs(*txp, dev->num_tx_queues). Both IFB
per-queue RX and TX stats live in those entries: ifb_xmit() updates
txp->rx_stats using the skb queue mapping, ifb_ri_tasklet() updates
txp->tx_stats, and ifb_stats64() aggregates both over
dev->num_tx_queues.

The ethtool stats callbacks instead size and walk the per-queue
stats with dev->real_num_rx_queues and dev->real_num_tx_queues. With
an asymmetric device where the RX queue count exceeds the TX queue
count, for example:

    ip link add name ifb10 numtxqueues 1 numrxqueues 8 type ifb
    ethtool -S ifb10

ifb_get_ethtool_stats() indexes past the tx_private allocation and
copies adjacent slab data through ETHTOOL_GSTATS.

Use dev->num_tx_queues consistently for the stats strings, the
stats count, and the stats data walks. This reports one RX stats
group and one TX stats group for each backing ifb_q_private entry,
which is the queue set IFB can actually populate.

Reproduced under UML+KASAN at v7.1-rc2:

  BUG: KASAN: slab-out-of-bounds in ifb_fill_stats_data+0x3c/0xae
  Read of size 8 at addr 0000000062dbd228 by task ethtool/36
  ifb_fill_stats_data+0x3c/0xae
  ifb_get_ethtool_stats+0xc0/0x129
  __dev_ethtool+0x1ca5/0x363c
  dev_ethtool+0x123/0x1b3
  dev_ioctl+0x56c/0x744
  sock_do_ioctl+0x15f/0x1b2
  sock_ioctl+0x4d5/0x50a
  sys_ioctl+0xd8b/0xde9

With the patch applied, the same UML+KASAN repro is silent and
ethtool -S ifb10 reports only the stats backed by the single
allocated tx_private entry.

Fixes: a21ee5b2fcb8 ("net: ifb: support ethtools stats")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Link: https://patch.msgid.link/20260514013739.3549624-1-michael.bommarito@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ifb.c

index 5407d2ed71b3531a0271344a03bf9e2d0d9fc1bd..43aa1bfd41cff23a02d67346ce8139b15c98e331 100644 (file)
@@ -211,12 +211,12 @@ static void ifb_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 
        switch (stringset) {
        case ETH_SS_STATS:
-               for (i = 0; i < dev->real_num_rx_queues; i++)
+               for (i = 0; i < dev->num_tx_queues; i++)
                        for (j = 0; j < IFB_Q_STATS_LEN; j++)
                                ethtool_sprintf(&p, "rx_queue_%u_%.18s",
                                                i, ifb_q_stats_desc[j].desc);
 
-               for (i = 0; i < dev->real_num_tx_queues; i++)
+               for (i = 0; i < dev->num_tx_queues; i++)
                        for (j = 0; j < IFB_Q_STATS_LEN; j++)
                                ethtool_sprintf(&p, "tx_queue_%u_%.18s",
                                                i, ifb_q_stats_desc[j].desc);
@@ -229,8 +229,7 @@ static int ifb_get_sset_count(struct net_device *dev, int sset)
 {
        switch (sset) {
        case ETH_SS_STATS:
-               return IFB_Q_STATS_LEN * (dev->real_num_rx_queues +
-                                         dev->real_num_tx_queues);
+               return IFB_Q_STATS_LEN * dev->num_tx_queues * 2;
        default:
                return -EOPNOTSUPP;
        }
@@ -262,12 +261,12 @@ static void ifb_get_ethtool_stats(struct net_device *dev,
        struct ifb_q_private *txp;
        int i;
 
-       for (i = 0; i < dev->real_num_rx_queues; i++) {
+       for (i = 0; i < dev->num_tx_queues; i++) {
                txp = dp->tx_private + i;
                ifb_fill_stats_data(&data, &txp->rx_stats);
        }
 
-       for (i = 0; i < dev->real_num_tx_queues; i++) {
+       for (i = 0; i < dev->num_tx_queues; i++) {
                txp = dp->tx_private + i;
                ifb_fill_stats_data(&data, &txp->tx_stats);
        }