stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y)
@ 2026-06-30  0:51 Annie Kim
  2026-06-30 22:23 ` Sasha Levin
                   ` (3 more replies)
  0 siblings, 4 replies; 12+ messages in thread
From: Annie Kim @ 2026-06-30  0:51 UTC (permalink / raw)
  To: stable; +Cc: mst, jasowang@redhat.com

Hello,

Hope this email finds you well. (Sorry I am resending it due to plaintext issue)

I am reporting a minor OOB write bug that was fixed in the mainline
kernel (commit c7114b1249fa) but is still missing from the stable LTS
trees (6.1.y, 6.6.y)
  - the fix: https://github.com/torvalds/linux/commit/86a48a00efdf61197b6658e52c6140463eb313dc
Please excuse me if this issue has already been acknowledged or deemed
non-critical. However, I am reporting it because this OOB write could
still be exploited by a malicious device or host OS to trigger
unexpected behavior in the guest VM.

Bug:
- drivers/net/virtio_net.c reads rss_max_indirection_table_length from
device config with no bound check, then uses it as a loop bound over a
fixed 128-entry array (indirection table) embedded in a kmalloc-512
buffer.
- A malicious device/hostOS can OOB write past the indirection table.
- Confirmed KASAN output (virtnet_init_default_rss is inlined into
virtnet_probe):
  BUG: KASAN: slab-out-of-bounds in virtnet_probe+0x2f46/0x3bc0
  Write of size 2 at addr ff110000bb9aed68 by task swapper/0/1

Impact:
most likely just guest kernel crash.
- At boot if the virtio-net device config reports
rss_max_indirection_table_length > 128, with values constrained to to
0..N-1 where N is the maximum number of vCPUs for the VM. (OOB write)
- At runtime if the guest runs "ethtool -X" on the buggy device.
Again, values are constrained to N. (OOB write, OOB read)

Exact files and affected code:
(Line numbers below are from 6.6.y (6.1.y is equivalent).)
drivers/net/virtio_net.c:223  #define VIRTIO_NET_RSS_MAX_TABLE_LEN 128
drivers/net/virtio_net.c:228  u16
indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];   (fixed-size array)
drivers/net/virtio_net.c:4816 vi->rss_indir_table_size =
virtio_cread16(... rss_max_indirection_table_length)   (unchecked
read)
drivers/net/virtio_net.c:3204 vi->ctrl->rss.indirection_table[i] =
indir_val;   (OOB write when size > 128, boot path)
drivers/net/virtio_net.c:3883 vi->ctrl->rss.indirection_table[i] =
rxfh->indir[i];   (OOB write, ethtool set_rxfh path)


Affected:
Trees containing c7114b1249fa (v5.18) but predating the fix (v6.13).
Confirmed by source inspection: 6.1.y, 6.6.y. Not affected: 6.12.y and
later (already fixed), 5.15.y and older (no virtio-net RSS).

To reproduce (I can send you the PoC if you need it):
Guest OS with VIRTIO_NET_F_RSS and UBSAN/KASAN; make QEMU return 512
for rss_max_indirection_table_length in virtio_net_get_config(); boot
triggers an out-of-bounds write report in virtnet_init_default_rss().

Proposed fix:
The canonical fix is the upstream commit 86a48a00efdf, which makes the
indirection table dynamically sized. Please apply 86a48a00efdf to
6.6.y and 6.1.y.

Thanks,
Annie Kim

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y)
  2026-06-30  0:51 [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y) Annie Kim
@ 2026-06-30 22:23 ` Sasha Levin
  2026-07-03 10:50   ` [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN Hyokyung Kim
  2026-07-03 10:52   ` [PATCH 6.1.y] " Hyokyung Kim
  2026-07-10 11:19 ` [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size Hyokyung Kim
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 12+ messages in thread
From: Sasha Levin @ 2026-06-30 22:23 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, mst, jasowang@redhat.com, Annie Kim

> The canonical fix is the upstream commit 86a48a00efdf, which makes the
> indirection table dynamically sized. Please apply 86a48a00efdf to
> 6.6.y and 6.1.y.

Could you send a tested backport please?

--
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN
  2026-06-30 22:23 ` Sasha Levin
@ 2026-07-03 10:50   ` Hyokyung Kim
  2026-07-04  2:05     ` Sasha Levin
  2026-07-03 10:52   ` [PATCH 6.1.y] " Hyokyung Kim
  1 sibling, 1 reply; 12+ messages in thread
From: Hyokyung Kim @ 2026-07-03 10:50 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Hyokyung Kim

virtnet_probe() reads rss_max_indirection_table_length from the device
config space into vi->rss_indir_table_size and later uses it as the
number of entries to write into the fixed-size 128-entry indirection
table in struct virtio_net_ctrl_rss (in virtnet_init_default_rss(), and
again in virtnet_set_rxfh()/virtnet_get_rxfh()), without validating it
against VIRTIO_NET_RSS_MAX_TABLE_LEN. A malicious or buggy device can
report a length larger than 128 and overflow the array, corrupting
adjacent slab memory. This is reachable at probe time, before the
interface is brought up.

This was fixed upstream by commit 86a48a00efdf ("virtio_net: Support
dynamic rss indirection table size"), which reworks the driver to
allocate the indirection table dynamically. However that change is too
large to backport to stable. Instead, clamp the device-advertised length
to VIRTIO_NET_RSS_MAX_TABLE_LEN: this solves the overflow with minimal
changes.

Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
---

Hi Sasha,

You asked for a tested backport of 86a48a00efdf to 6.6.y and 6.1.y.
While preparing it I found the code does not backport cleanly (there
are many lines needed to change). To minimize the risks of introducing
new bugs, instead I added a small 6-line bounds check on the length the
driver reads from the buggy or malicious device. Sending one patch per
tree.

Tested with KASAN + UBSAN under QEMU (guest 6.6.143), using a virtio-net
device that advertises rss_max_indirection_table_length=512, i.e. larger
than the driver's 128-entry VIRTIO_NET_RSS_MAX_TABLE_LEN.

Before this patch, virtnet_probe() overflows the fixed indirection_table[]
at boot:

  BUG: KASAN: slab-out-of-bounds in virtnet_probe+0x136e/0x1520
  Write of size 2 at addr ff11000003384168 by task swapper/0/1
  CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.6.143 #2
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
  Call Trace:
   <TASK>
   dump_stack_lvl+0x36/0x50
   print_report+0xcf/0x670
   kasan_report+0xc7/0x100
   virtnet_probe+0x136e/0x1520
   virtio_dev_probe+0x2da/0x470
   really_probe+0x12f/0x420
   __driver_probe_device+0xf8/0x1e0
   driver_probe_device+0x49/0x190
   __driver_attach+0xdd/0x290
   bus_for_each_dev+0xde/0x140
   bus_add_driver+0x14a/0x2e0
   driver_register+0x9b/0x1c0
   virtio_net_driver_init+0x89/0xb0
   do_one_initcall+0x9e/0x2d0

After this patch the length is clamped, the device still probes, the boot
is clean (no KASAN report), and ethtool -x reports a 128-entry table:

  virtio_net virtio0: rss_max_indirection_table_length=512 exceeds max 128, clamping

 drivers/net/virtio_net.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 33f61922c139..ec07e289f0c8 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -4587,6 +4587,12 @@ static int virtnet_probe(struct virtio_device *vdev)
 		vi->rss_indir_table_size =
 			virtio_cread16(vdev, offsetof(struct virtio_net_config,
 				rss_max_indirection_table_length));
+		if (vi->rss_indir_table_size > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+			dev_warn(&vdev->dev,
+				 "rss_max_indirection_table_length=%u exceeds max %u, clamping\n",
+				 vi->rss_indir_table_size, VIRTIO_NET_RSS_MAX_TABLE_LEN);
+			vi->rss_indir_table_size = VIRTIO_NET_RSS_MAX_TABLE_LEN;
+		}
 	}
 
 	if (vi->has_rss || vi->has_rss_hash_report) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6.1.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN
  2026-06-30 22:23 ` Sasha Levin
  2026-07-03 10:50   ` [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN Hyokyung Kim
@ 2026-07-03 10:52   ` Hyokyung Kim
  2026-08-20 13:49     ` Greg KH
  1 sibling, 1 reply; 12+ messages in thread
From: Hyokyung Kim @ 2026-07-03 10:52 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Hyokyung Kim

virtnet_probe() reads rss_max_indirection_table_length from the device
config space into vi->rss_indir_table_size and later uses it as the
number of entries to write into the fixed-size 128-entry indirection
table in struct virtio_net_ctrl_rss (in virtnet_init_default_rss(), and
again in virtnet_set_rxfh()/virtnet_get_rxfh()), without validating it
against VIRTIO_NET_RSS_MAX_TABLE_LEN. A malicious or buggy device can
report a length larger than 128 and overflow the array, corrupting
adjacent slab memory. This is reachable at probe time, before the
interface is brought up.

This was fixed upstream by commit 86a48a00efdf ("virtio_net: Support
dynamic rss indirection table size"), which reworks the driver to
allocate the indirection table dynamically. However that change is too
large to backport to stable. Instead, clamp the device-advertised length
to VIRTIO_NET_RSS_MAX_TABLE_LEN: this solves the overflow with minimal
changes.

Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
---

Hi Sasha,

You asked for a tested backport of 86a48a00efdf to 6.6.y and 6.1.y.
While preparing it I found the code does not backport cleanly (there
are many lines needed to change). To minimize the risks of introducing
new bugs, instead I added a small 6-line bounds check on the length the
driver reads from the buggy or malicious device. Sending one patch per
tree.

Tested with KASAN + UBSAN under QEMU (guest 6.1.176), using a virtio-net
device that advertises rss_max_indirection_table_length=512, i.e. larger
than the driver's 128-entry VIRTIO_NET_RSS_MAX_TABLE_LEN.

Before this patch, virtnet_probe() overflows the fixed indirection_table[]
at boot:

  BUG: KASAN: slab-out-of-bounds in virtnet_probe+0x11a2/0x1580
  Write of size 2 at addr ff11000004130d60 by task swapper/0/1
  CPU: 1 PID: 1 Comm: swapper/0 Not tainted 6.1.176 #1
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
  Call Trace:
   <TASK>
   dump_stack_lvl+0x37/0x4a
   print_report+0x181/0x49e
   kasan_report+0xc9/0x150
   virtnet_probe+0x11a2/0x1580
   virtio_dev_probe+0x2da/0x470
   really_probe+0x12f/0x390
   __driver_probe_device+0xfa/0x1a0
   driver_probe_device+0x49/0x190
   __driver_attach+0xdd/0x290
   bus_for_each_dev+0xf5/0x150
   bus_add_driver+0x26e/0x2c0
   driver_register+0x10c/0x1a0
   virtio_net_driver_init+0x6c/0x93
   do_one_initcall+0x9e/0x2c0

After this patch the length is clamped, the device still probes, the boot
is clean (no KASAN report), and ethtool -x reports a 128-entry table:

  virtio_net virtio0: rss_max_indirection_table_length=512 exceeds max 128, clamping

 drivers/net/virtio_net.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b62b76963137..c840e6a55d86 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -3913,6 +3913,12 @@ static int virtnet_probe(struct virtio_device *vdev)
 		vi->rss_indir_table_size =
 			virtio_cread16(vdev, offsetof(struct virtio_net_config,
 				rss_max_indirection_table_length));
+		if (vi->rss_indir_table_size > VIRTIO_NET_RSS_MAX_TABLE_LEN) {
+			dev_warn(&vdev->dev,
+				 "rss_max_indirection_table_length=%u exceeds max %u, clamping\n",
+				 vi->rss_indir_table_size, VIRTIO_NET_RSS_MAX_TABLE_LEN);
+			vi->rss_indir_table_size = VIRTIO_NET_RSS_MAX_TABLE_LEN;
+		}
 	}
 
 	if (vi->has_rss || vi->has_rss_hash_report) {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN
  2026-07-03 10:50   ` [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN Hyokyung Kim
@ 2026-07-04  2:05     ` Sasha Levin
  2026-07-06  5:48       ` Annie Kim
  0 siblings, 1 reply; 12+ messages in thread
From: Sasha Levin @ 2026-07-04  2:05 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Hyokyung Kim

On Thu, Jul 03, 2026 at 07:50:59PM +0900, Hyokyung Kim wrote:
> This was fixed upstream by commit 86a48a00efdf ("virtio_net: Support
> dynamic rss indirection table size"), which reworks the driver to
> allocate the indirection table dynamically. However that change is too
> large to backport to stable. Instead, clamp the device-advertised length

Thanks for working on this, and for the KASAN/UBSAN testing. However, rather
than a stable-only clamp that deviates from what upstream did, I'd prefer a
proper backport of 86a48a00efdf ("virtio_net: Support dynamic rss indirection
table size") with the conflicts resolved for 6.6.y and 6.1.y. Staying aligned
with upstream keeps future backports to these trees from getting harder, and
avoids carrying behavior that was never reviewed upstream.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN
  2026-07-04  2:05     ` Sasha Levin
@ 2026-07-06  5:48       ` Annie Kim
  0 siblings, 0 replies; 12+ messages in thread
From: Annie Kim @ 2026-07-06  5:48 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang

> Thanks for working on this, and for the KASAN/UBSAN testing. However, rather
> than a stable-only clamp that deviates from what upstream did, I'd prefer a
> proper backport of 86a48a00efdf

Hi Sasha,

Thanks for your reply.

Sorry, this is my first time submitting a patch,
so I was unsure whether it would be better to ask for your preference first -
between a clamp and a backport.

I understand now that the preferred approach is to prepare the backport.
I’ll send a tested backport once it is ready.

Thanks!
Annie Kim

On Sat, Jul 4, 2026 at 11:06 AM Sasha Levin <sashal@kernel.org> wrote:
>
> On Thu, Jul 03, 2026 at 07:50:59PM +0900, Hyokyung Kim wrote:
> > This was fixed upstream by commit 86a48a00efdf ("virtio_net: Support
> > dynamic rss indirection table size"), which reworks the driver to
> > allocate the indirection table dynamically. However that change is too
> > large to backport to stable. Instead, clamp the device-advertised length
>
> Thanks for working on this, and for the KASAN/UBSAN testing. However, rather
> than a stable-only clamp that deviates from what upstream did, I'd prefer a
> proper backport of 86a48a00efdf ("virtio_net: Support dynamic rss indirection
> table size") with the conflicts resolved for 6.6.y and 6.1.y. Staying aligned
> with upstream keeps future backports to these trees from getting harder, and
> avoids carrying behavior that was never reviewed upstream.
>
> --
> Thanks,
> Sasha

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size
  2026-06-30  0:51 [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y) Annie Kim
  2026-06-30 22:23 ` Sasha Levin
@ 2026-07-10 11:19 ` Hyokyung Kim
  2026-07-10 21:03   ` Sasha Levin
  2026-07-10 11:25 ` [PATCH 6.1.y] " Hyokyung Kim
  2026-07-10 12:49 ` [PATCH 6.6.y] " Hyokyung Kim
  3 siblings, 1 reply; 12+ messages in thread
From: Hyokyung Kim @ 2026-07-10 11:19 UTC (permalink / raw)
  To: stable
  Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Philo Lu, Xuan Zhuo,
	Joe Damato, Paolo Abeni, Hyokyung Kim

From: Philo Lu <lulie@linux.alibaba.com>

commit 86a48a00efdf61197b6658e52c6140463eb313dc upstream.

When reading/writing virtio_net_ctrl_rss, the indirection table size is
obtained from vi->rss_indir_table_size, initialized during virtnet_probe().
However, the indirection_table was statically sized as
VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
vi->rss_indir_table_size exceeds this limit.

This patch implements dynamic allocation for the indirection table,
allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
and freed in virtnet_remove().

In virtnet_commit_rss_command(), scatter-gather lists for RSS are
initialized differently based on hash_report presence, so indirection_table
is unused when !vi->has_rss. Therefore, allocation is unnecessary for
hash_report-only scenarios.

Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Joe Damato <jdamato@fastly.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
[ Hyokyung Kim: 6.6.y predates the refactor that moved the RSS config into
  struct virtnet_info, so struct virtio_net_ctrl_rss is still embedded in
  struct control_buf and reached through the heap-allocated vi->ctrl. Every
  adaptation below follows from that single difference:
  - the new allocation and all indirection_table accesses use vi->ctrl->rss
    in place of upstream's vi->rss;
  - because vi->ctrl is allocated in virtnet_alloc_queues() (via init_vqs())
    and freed in virtnet_free_queues(), the table is allocated and freed there
    too, not in virtnet_probe()/virtnet_remove(), so its lifetime tracks
    vi->ctrl across the probe error-unwind and freeze/restore paths;
  - since freeing the table now dereferences vi->ctrl, vi->ctrl is set to NULL
    after each kfree so a re-entered virtnet_free_queues() cannot dereference
    or free a stale pointer;
  - the table is allocated with kcalloc() so it is zero-filled when
    reallocated on the restore path (upstream never reallocates it). ]
Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
---
 drivers/net/virtio_net.c | 43 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 38 insertions(+), 5 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 33f61922c1..5bcd129685 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -208,15 +208,16 @@ struct receive_queue {
  * because table sizes may be differ according to the device configuration.
  */
 #define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
-#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
 struct virtio_net_ctrl_rss {
 	u32 hash_types;
 	u16 indirection_table_mask;
 	u16 unclassified_queue;
-	u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+	u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
 	u16 max_tx_vq;
 	u8 hash_key_length;
 	u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+
+	u16 *indirection_table;
 };
 
 /* Control VQ buffers: protected by the rtnl lock */
@@ -3011,6 +3012,25 @@ static int virtnet_set_ringparam(struct net_device *dev,
 	return 0;
 }
 
+static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
+{
+	if (!indir_table_size) {
+		rss->indirection_table = NULL;
+		return 0;
+	}
+
+	rss->indirection_table = kcalloc(indir_table_size, sizeof(u16), GFP_KERNEL);
+	if (!rss->indirection_table)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
+{
+	kfree(rss->indirection_table);
+}
+
 static bool virtnet_commit_rss_command(struct virtnet_info *vi)
 {
 	struct net_device *dev = vi->dev;
@@ -3020,11 +3040,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
 	/* prepare sgs */
 	sg_init_table(sgs, 4);
 
-	sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
+	sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
 	sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
 
-	sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
-	sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+	if (vi->has_rss) {
+		sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
+		sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+	} else {
+		sg_set_buf(&sgs[1], &vi->ctrl->rss.hash_cfg_reserved, sizeof(uint16_t));
+	}
 
 	sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
 			- offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
@@ -4080,7 +4104,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 
 	kfree(vi->rq);
 	kfree(vi->sq);
+	if (vi->ctrl)
+		rss_indirection_table_free(&vi->ctrl->rss);
 	kfree(vi->ctrl);
+	vi->ctrl = NULL;
 }
 
 static void _free_receive_bufs(struct virtnet_info *vi)
@@ -4266,6 +4293,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
 		vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
 		if (!vi->ctrl)
 			goto err_ctrl;
+		if ((vi->has_rss || vi->has_rss_hash_report) &&
+		    rss_indirection_table_alloc(&vi->ctrl->rss, vi->rss_indir_table_size))
+			goto err_sq;
 	} else {
 		vi->ctrl = NULL;
 	}
@@ -4298,7 +4328,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
 err_rq:
 	kfree(vi->sq);
 err_sq:
+	if (vi->ctrl)
+		rss_indirection_table_free(&vi->ctrl->rss);
 	kfree(vi->ctrl);
+	vi->ctrl = NULL;
 err_ctrl:
 	return -ENOMEM;
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6.1.y] virtio_net: Support dynamic rss indirection table size
  2026-06-30  0:51 [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y) Annie Kim
  2026-06-30 22:23 ` Sasha Levin
  2026-07-10 11:19 ` [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size Hyokyung Kim
@ 2026-07-10 11:25 ` Hyokyung Kim
  2026-07-10 21:03   ` Sasha Levin
  2026-07-10 12:49 ` [PATCH 6.6.y] " Hyokyung Kim
  3 siblings, 1 reply; 12+ messages in thread
From: Hyokyung Kim @ 2026-07-10 11:25 UTC (permalink / raw)
  To: stable
  Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Philo Lu, Xuan Zhuo,
	Joe Damato, Paolo Abeni, Hyokyung Kim

From: Philo Lu <lulie@linux.alibaba.com>

commit 86a48a00efdf61197b6658e52c6140463eb313dc upstream.

When reading/writing virtio_net_ctrl_rss, the indirection table size is
obtained from vi->rss_indir_table_size, initialized during virtnet_probe().
However, the indirection_table was statically sized as
VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
vi->rss_indir_table_size exceeds this limit.

This patch implements dynamic allocation for the indirection table,
allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
and freed in virtnet_remove().

In virtnet_commit_rss_command(), scatter-gather lists for RSS are
initialized differently based on hash_report presence, so indirection_table
is unused when !vi->has_rss. Therefore, allocation is unnecessary for
hash_report-only scenarios.

Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Acked-by: Joe Damato <jdamato@fastly.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
[ Hyokyung Kim: 6.1.y predates the refactor that moved the RSS config into
  struct virtnet_info, so struct virtio_net_ctrl_rss is still embedded in
  struct control_buf and reached through the heap-allocated vi->ctrl. Every
  adaptation below follows from that single difference:
  - the new allocation and all indirection_table accesses use vi->ctrl->rss
    in place of upstream's vi->rss;
  - because vi->ctrl is allocated in virtnet_alloc_queues() (via init_vqs())
    and freed in virtnet_free_queues(), the table is allocated and freed there
    too, not in virtnet_probe()/virtnet_remove(), so its lifetime tracks
    vi->ctrl across the probe error-unwind and freeze/restore paths;
  - since freeing the table now dereferences vi->ctrl, vi->ctrl is set to NULL
    after each kfree so a re-entered virtnet_free_queues() cannot dereference
    or free a stale pointer;
  - the table is allocated with kcalloc() so it is zero-filled when
    reallocated on the restore path (upstream never reallocates it). ]
Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
---
 drivers/net/virtio_net.c | 43 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 38 insertions(+), 5 deletions(-)

diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b62b769631..2fb00df795 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -179,15 +179,16 @@ struct receive_queue {
  * because table sizes may be differ according to the device configuration.
  */
 #define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
-#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
 struct virtio_net_ctrl_rss {
 	u32 hash_types;
 	u16 indirection_table_mask;
 	u16 unclassified_queue;
-	u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
+	u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
 	u16 max_tx_vq;
 	u8 hash_key_length;
 	u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
+
+	u16 *indirection_table;
 };
 
 /* Control VQ buffers: protected by the rtnl lock */
@@ -2488,6 +2489,25 @@ static int virtnet_set_ringparam(struct net_device *dev,
 	return 0;
 }
 
+static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
+{
+	if (!indir_table_size) {
+		rss->indirection_table = NULL;
+		return 0;
+	}
+
+	rss->indirection_table = kcalloc(indir_table_size, sizeof(u16), GFP_KERNEL);
+	if (!rss->indirection_table)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
+{
+	kfree(rss->indirection_table);
+}
+
 static bool virtnet_commit_rss_command(struct virtnet_info *vi)
 {
 	struct net_device *dev = vi->dev;
@@ -2497,11 +2517,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
 	/* prepare sgs */
 	sg_init_table(sgs, 4);
 
-	sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
+	sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
 	sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
 
-	sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
-	sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+	if (vi->has_rss) {
+		sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
+		sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
+	} else {
+		sg_set_buf(&sgs[1], &vi->ctrl->rss.hash_cfg_reserved, sizeof(uint16_t));
+	}
 
 	sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
 			- offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
@@ -3415,7 +3439,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
 
 	kfree(vi->rq);
 	kfree(vi->sq);
+	if (vi->ctrl)
+		rss_indirection_table_free(&vi->ctrl->rss);
 	kfree(vi->ctrl);
+	vi->ctrl = NULL;
 }
 
 static void _free_receive_bufs(struct virtnet_info *vi)
@@ -3610,6 +3637,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
 		vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
 		if (!vi->ctrl)
 			goto err_ctrl;
+		if ((vi->has_rss || vi->has_rss_hash_report) &&
+		    rss_indirection_table_alloc(&vi->ctrl->rss, vi->rss_indir_table_size))
+			goto err_sq;
 	} else {
 		vi->ctrl = NULL;
 	}
@@ -3642,7 +3672,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
 err_rq:
 	kfree(vi->sq);
 err_sq:
+	if (vi->ctrl)
+		rss_indirection_table_free(&vi->ctrl->rss);
 	kfree(vi->ctrl);
+	vi->ctrl = NULL;
 err_ctrl:
 	return -ENOMEM;
 }
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size
  2026-06-30  0:51 [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y) Annie Kim
                   ` (2 preceding siblings ...)
  2026-07-10 11:25 ` [PATCH 6.1.y] " Hyokyung Kim
@ 2026-07-10 12:49 ` Hyokyung Kim
  3 siblings, 0 replies; 12+ messages in thread
From: Hyokyung Kim @ 2026-07-10 12:49 UTC (permalink / raw)
  To: stable; +Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang

Hi Sasha,

Forgot to include the test details - 
sending a follow up e-mail just in case it helps!
 
Tested with KASAN (inline) under QEMU
(guests 6.6.144 and 6.1.177), using a virtio-net device that advertises
rss_max_indirection_table_length=512, i.e. larger than the driver's
128-entry VIRTIO_NET_RSS_MAX_TABLE_LEN.

Boot time testing:
  - unpatched: KASAN slab-out-of-bounds write in virtnet_probe (both trees)
  - patched: clean, no KASAN report.

Runtime testing:
  - patched: rewriting the full 512-entry table via ETHTOOL_SRXFHINDIR
             (reset and explicit full table) reports no KASAN bug.

Thanks,
Annie Kim

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size
  2026-07-10 11:19 ` [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size Hyokyung Kim
@ 2026-07-10 21:03   ` Sasha Levin
  0 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-07-10 21:03 UTC (permalink / raw)
  To: stable
  Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Philo Lu, Xuan Zhuo,
	Joe Damato, Paolo Abeni, Hyokyung Kim

On Fri, Jul 10, 2026 at 11:19:54AM +0000, Hyokyung Kim wrote:
> However, the indirection_table was statically sized as
> VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
> vi->rss_indir_table_size exceeds this limit.
>
> This patch implements dynamic allocation for the indirection table,
> allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
> and freed in virtnet_remove().

Queued for 6.6, thanks.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 6.1.y] virtio_net: Support dynamic rss indirection table size
  2026-07-10 11:25 ` [PATCH 6.1.y] " Hyokyung Kim
@ 2026-07-10 21:03   ` Sasha Levin
  0 siblings, 0 replies; 12+ messages in thread
From: Sasha Levin @ 2026-07-10 21:03 UTC (permalink / raw)
  To: stable
  Cc: Sasha Levin, Michael S . Tsirkin, Jason Wang, Philo Lu, Xuan Zhuo,
	Joe Damato, Paolo Abeni, Hyokyung Kim

On Fri, Jul 10, 2026 at 11:25:21AM +0000, Hyokyung Kim wrote:
> However, the indirection_table was statically sized as
> VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
> vi->rss_indir_table_size exceeds this limit.
>
> This patch implements dynamic allocation for the indirection table,
> allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
> and freed in virtnet_remove().

Queued for 6.1, thanks.

-- 
Thanks,
Sasha

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 6.1.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN
  2026-07-03 10:52   ` [PATCH 6.1.y] " Hyokyung Kim
@ 2026-08-20 13:49     ` Greg KH
  0 siblings, 0 replies; 12+ messages in thread
From: Greg KH @ 2026-08-20 13:49 UTC (permalink / raw)
  To: Hyokyung Kim; +Cc: stable, Sasha Levin, Michael S . Tsirkin, Jason Wang

On Fri, Jul 03, 2026 at 07:52:56PM +0900, Hyokyung Kim wrote:
> virtnet_probe() reads rss_max_indirection_table_length from the device
> config space into vi->rss_indir_table_size and later uses it as the
> number of entries to write into the fixed-size 128-entry indirection
> table in struct virtio_net_ctrl_rss (in virtnet_init_default_rss(), and
> again in virtnet_set_rxfh()/virtnet_get_rxfh()), without validating it
> against VIRTIO_NET_RSS_MAX_TABLE_LEN. A malicious or buggy device can
> report a length larger than 128 and overflow the array, corrupting
> adjacent slab memory. This is reachable at probe time, before the
> interface is brought up.
> 
> This was fixed upstream by commit 86a48a00efdf ("virtio_net: Support
> dynamic rss indirection table size"), which reworks the driver to
> allocate the indirection table dynamically. However that change is too
> large to backport to stable. Instead, clamp the device-advertised length
> to VIRTIO_NET_RSS_MAX_TABLE_LEN: this solves the overflow with minimal
> changes.

Why is it "too large"?  Again, we want to keep as close as possible to
upstream as diverging will cause bugs and maintenance problems over
time.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-08-20 14:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-30  0:51 [LTS Backport Request] Fix RSS indirection table OOB write (6.1.y, 6.6.y) Annie Kim
2026-06-30 22:23 ` Sasha Levin
2026-07-03 10:50   ` [PATCH 6.6.y] virtio_net: clamp rss_indir_table_size to VIRTIO_NET_RSS_MAX_TABLE_LEN Hyokyung Kim
2026-07-04  2:05     ` Sasha Levin
2026-07-06  5:48       ` Annie Kim
2026-07-03 10:52   ` [PATCH 6.1.y] " Hyokyung Kim
2026-08-20 13:49     ` Greg KH
2026-07-10 11:19 ` [PATCH 6.6.y] virtio_net: Support dynamic rss indirection table size Hyokyung Kim
2026-07-10 21:03   ` Sasha Levin
2026-07-10 11:25 ` [PATCH 6.1.y] " Hyokyung Kim
2026-07-10 21:03   ` Sasha Levin
2026-07-10 12:49 ` [PATCH 6.6.y] " Hyokyung Kim

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).