From: Przemek Kitszel <przemyslaw.kitszel@intel.com>
To: netdev@vger.kernel.org, Jakub Kicinski <kuba@kernel.org>
Cc: Tony Nguyen <anthony.l.nguyen@intel.com>,
Aleksandr Loktionov <aleksandr.loktionov@intel.com>,
Michal Schmidt <mschmidt@redhat.com>,
intel-wired-lan@lists.osuosl.org, edumazet@google.com,
horms@kernel.org, pabeni@redhat.com, davem@davemloft.net,
Przemek Kitszel <przemyslaw.kitszel@intel.com>
Subject: [PATCH net v5 6/6] ice: size ring stats arrays from the final queue count
Date: Fri, 25 Sep 2026 15:15:48 +0200 [thread overview]
Message-ID: <20260925132636.123300-7-przemyslaw.kitszel@intel.com> (raw)
In-Reply-To: <20260925132636.123300-1-przemyslaw.kitszel@intel.com>
The ring stats arrays were sized in one place and indexed in another,
with nothing reconciling the two. ice_vsi_alloc_stat_arrays() gave up as
soon as a container existed:
if (pf->vsi_stats[vsi->idx])
/* realloc will happen in rebuild path */
return 0;
while ice_vsi_alloc_ring_stats() walks the arrays with
ice_for_each_alloc_txq() / ice_for_each_alloc_rxq(), that is, up to
vsi->alloc_txq / vsi->alloc_rxq. Whenever the arrays are shorter than
the count ice_vsi_set_num_qs() ends up computing, that loop reads and
stores past the end of the kmalloc'ed pointer arrays.
Deferring to "the rebuild path" does not hold. It cannot get the size
right, and some paths never call it at all.
ice_devlink_reinit_down() is one of the latter. It calls ice_vsi_decfg()
directly, which does not free pf->vsi_stats[], and nothing on the way
down releases the main VSI's entry either: ice_dealloc_vsis() runs only
from ice_init()/ice_deinit(), and the single entry that ice_unload()
does drop is the control VSI's, via ice_deinit_fdir(). The main VSI's
arrays therefore survive the reload, while ice_devlink_reinit_up() runs
ice_vsi_cfg() and recomputes the count from
netif_get_num_default_rss_queues(), which follows cpu_online_mask.
Sizing the arrays with most CPUs offline and then onlining them is
enough, no VF involved:
for c in /sys/devices/system/cpu/cpu[0-9]*/online; do echo 0 > $c; done
echo 0000:18:00.0 > /sys/bus/pci/drivers/ice/unbind
echo 0000:18:00.0 > /sys/bus/pci/drivers/ice/bind
for c in /sys/devices/system/cpu/cpu[0-9]*/online; do echo 1 > $c; done
devlink dev reload pci/0000:18:00.0 action driver_reinit
The unbind/bind is what makes the arrays actually be allocated at the
small size; a reload alone only reuses them.
The read then runs off the end of tx_ring_stats[] and picks up whatever
follows it in kmalloc-32. Here that was a string, 0x74756f5f6c697475
spelling "util_out" in memory order. It is stored into ring->ring_stats
and faults on the first dereference, in ice_setup_tx_ring(), call trace:
RIP: 0010:ice_setup_tx_ring+0x8d/0xe0 [ice]
ice_vsi_setup_tx_rings+0x2a/0x80 [ice]
ice_vsi_open+0x28/0x170 [ice]
ice_open_internal+0xc9/0x160 [ice]
__dev_open+0x138/0x2b0
__dev_change_flags+0x1d5/0x250
netif_change_flags+0x21/0x60
do_setlink.constprop.0+0x336/0xcf0
rtnl_newlink+0x4a4/0x9b0
Even where the rebuild path does run, it sizes the arrays before
ice_vsi_decfg() returns the queues to the PF pool, and for an
ICE_VSI_PF VSI with no explicit request it derives the count from that
shared pool. Nothing serializes it against the recount in
ice_vsi_set_num_qs(), so a concurrent release, say
"echo 0 > sriov_numvfs", leaves the final count larger than the arrays
that were already installed.
ice_vsi_alloc_stat_arrays() runs from ice_vsi_cfg_def(), right after
ice_vsi_alloc_def() called ice_vsi_set_num_qs(), so it is the first
place where the queue count is final. Make it the only authority: keep
the existing arrays when they are already long enough, and otherwise
grow them with ice_vsi_install_stat_arrays(), which carries the
surviving entries over. The check only forces a grow: while both arrays
are long enough they are kept, an oversized one being merely wasteful.
Once either is too short the whole container is replaced, and then the
other one follows the final count too, shrinking if that is what it
takes.
Michal Schmidt hit the same corruption through the VF path, where a
guest raises its queue count with VIRTCHNL_OP_REQUEST_QUEUES and the
following VF reset reconfigures the VSI with the larger count while the
old, shorter arrays are still installed:
BUG: KASAN: slab-out-of-bounds in ice_vsi_alloc_ring_stats+0x385/0x4a0 [ice]
Workqueue: ice ice_service_task [ice]
Call Trace:
kasan_report+0xd7/0x120
ice_vsi_alloc_ring_stats+0x385/0x4a0 [ice]
ice_vsi_cfg_def+0x12e2/0x2060 [ice]
ice_vsi_cfg+0xb5/0x3c0 [ice]
ice_reset_vf+0x858/0xf80 [ice]
ice_vc_request_qs_msg+0x1da/0x290 [ice]
ice_vc_process_vf_msg+0xb15/0x1430 [ice]
__ice_clean_ctrlq+0x70d/0x9d0 [ice]
ice_service_task+0x840/0xf20 [ice]
process_one_work+0x690/0xff0
worker_thread+0x4d9/0xd20
kthread+0x322/0x410
ret_from_fork+0x332/0x660
ret_from_fork_asm+0x1a/0x30
Allocated by task 2439:
kasan_save_stack+0x1c/0x40
kasan_save_track+0x10/0x30
__kasan_kmalloc+0x96/0xb0
__kmalloc_noprof+0x1d8/0x580
ice_vsi_cfg_def+0x115c/0x2060 [ice]
ice_vsi_cfg+0xb5/0x3c0 [ice]
ice_vsi_setup+0x180/0x320 [ice]
ice_start_vfs+0x1f3/0x590 [ice]
ice_ena_vfs+0x66d/0x798 [ice]
ice_sriov_configure.cold+0xe4/0x121 [ice]
sriov_numvfs_store+0x279/0x480
kernfs_fop_write_iter+0x331/0x4f0
vfs_write+0x4c4/0xe40
ksys_write+0x10c/0x240
do_syscall_64+0xd9/0x650
entry_SYSCALL_64_after_hwframe+0x76/0x7e
The buggy address belongs to the object at ffff88810affea40
which belongs to the cache kmalloc-32 of size 32
The buggy address is located 0 bytes to the right of
allocated 32-byte region [ffff88810affea40, ffff88810affea60)
Fixes: 288ecf491b16 ("ice: Accumulate ring statistics over reset")
Reported-by: Michal Schmidt <mschmidt@redhat.com>
Closes: https://redhat.atlassian.net/browse/RHEL-164321
Signed-off-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
---
v5:
- new patch, replaces the VF-only fix with one that covers every path
reaching ice_vsi_alloc_ring_stats() (Clashiko)
- the reproducers both postdate the cited tag: devlink reinit arrived
with 31c8db2c4fa7 ("ice: implement devlink reinit action"), the VF
path with 2a2cb4c6c181 ("ice: replace ice_vf_recreate_vsi() with
ice_vf_reconfig_vsi()"). The sizing itself went wrong in the cited
commit, hence the older tag (Clashiko)
- drop the follow-up VF resize patch, it could abort a VFLR after the
hardware had already reset the VF (Clashiko)
---
drivers/net/ethernet/intel/ice/ice_lib.c | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index 448d3c7780ad..c393d913d037 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -634,27 +634,29 @@ static int ice_vsi_install_stat_arrays(struct ice_vsi *vsi, u16 txq, u16 rxq)
/**
* ice_vsi_alloc_stat_arrays - Allocate statistics arrays
* @vsi: VSI pointer
+ *
+ * Runs after ice_vsi_set_num_qs(), so this is the first point where the queue
+ * count is final. Grow the arrays if an earlier sizing guessed too low.
+ *
+ * Return: 0 on success, negative error code otherwise.
*/
static int ice_vsi_alloc_stat_arrays(struct ice_vsi *vsi)
{
- struct ice_vsi_stats *vsi_stat;
+ struct ice_vsi_stats *old_stat;
struct ice_pf *pf = vsi->back;
if (vsi->type == ICE_VSI_CHNL)
return 0;
if (!pf->vsi_stats)
return -ENOENT;
- if (pf->vsi_stats[vsi->idx])
- /* realloc will happen in rebuild path */
+ old_stat = pf->vsi_stats[vsi->idx];
+ if (old_stat && old_stat->tx_ring_stats_len >= vsi->alloc_txq &&
+ old_stat->rx_ring_stats_len >= vsi->alloc_rxq)
return 0;
- vsi_stat = ice_vsi_new_stat_arrays(vsi->alloc_txq, vsi->alloc_rxq);
- if (!vsi_stat)
- return -ENOMEM;
-
- pf->vsi_stats[vsi->idx] = vsi_stat;
- return 0;
+ return ice_vsi_install_stat_arrays(vsi, vsi->alloc_txq,
+ vsi->alloc_rxq);
}
/**
--
2.51.1
next prev parent reply other threads:[~2026-09-25 13:27 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 13:15 [PATCH net v5 0/6] ice: fix stats array overflow via proper realloc Przemek Kitszel
2026-09-25 13:15 ` [PATCH net v5 1/6] ice: skip stats handling for channel VSIs on rebuild Przemek Kitszel
2026-09-25 14:29 ` Loktionov, Aleksandr
2026-09-29 14:04 ` netdev-bot+sashiko
2026-09-30 11:54 ` Przemek Kitszel
2026-09-29 18:02 ` Jacob Keller
2026-09-25 13:15 ` [PATCH net v5 2/6] ice: extract __ice_vsi_free_stats() Przemek Kitszel
2026-09-25 14:30 ` Loktionov, Aleksandr
2026-09-29 14:04 ` netdev-bot+sashiko
2026-09-30 11:54 ` Przemek Kitszel
2026-09-25 13:15 ` [PATCH net v5 3/6] ice: extract ice_vsi_new_stat_arrays() Przemek Kitszel
2026-09-25 14:30 ` Loktionov, Aleksandr
2026-09-25 13:15 ` [PATCH net v5 4/6] ice: extract ice_vsi_get_num_qs() Przemek Kitszel
2026-09-25 14:31 ` Loktionov, Aleksandr
2026-09-25 13:15 ` [PATCH net v5 5/6] ice: rebuild ring stats arrays instead of reallocating them in place Przemek Kitszel
2026-09-25 14:32 ` Loktionov, Aleksandr
2026-09-29 14:04 ` netdev-bot+sashiko
2026-09-30 11:54 ` Przemek Kitszel
2026-09-25 13:15 ` Przemek Kitszel [this message]
2026-09-25 14:32 ` [PATCH net v5 6/6] ice: size ring stats arrays from the final queue count Loktionov, Aleksandr
2026-09-29 14:04 ` netdev-bot+sashiko
2026-09-30 11:54 ` Przemek Kitszel
2026-09-30 11:55 ` [PATCH net v5 0/6] ice: fix stats array overflow via proper realloc Przemek Kitszel
2026-09-30 21:01 ` Jakub Kicinski
2026-09-30 21:10 ` patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260925132636.123300-7-przemyslaw.kitszel@intel.com \
--to=przemyslaw.kitszel@intel.com \
--cc=aleksandr.loktionov@intel.com \
--cc=anthony.l.nguyen@intel.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=intel-wired-lan@lists.osuosl.org \
--cc=kuba@kernel.org \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox