Thread (2 messages) flat view 2 messages, 2 authors, 7d ago

Re: [PATCH net] net: pktgen: use a consistent flow count

From: Paolo Abeni <pabeni@redhat.com>
Date: 2026-08-06 09:54:29
Also in: lkml, stable

On 8/2/26 5:23 PM, Qi Zhang wrote:
quoted hunk ↗ jump to hunk
From: Chengfeng Ye <redacted>

pktgen_if_write() can update cflows while the packet generator thread is
inside mod_cur_headers(). The latter first tests cflows, but f_pick() then
reloads it when selecting a random flow.

This allows the following interleaving:

  CPU 0 (kpktgend)                 CPU 1 (proc write)
  if (pkt_dev->cflows) // 10
                                   pkt_dev->cflows = 0
  get_random_u32_below(pkt_dev->cflows)

get_random_u32_below(0) returns a full-width random value. Using that
value as an index into the fixed-size flows array causes an out-of-bounds
access. The kernel reported:

  BUG: unable to handle page fault for address: ffffc8fe2d2674bc
  #PF: supervisor read access in kernel mode
  Oops: Oops: 0000 [#1] SMP KASAN NOPTI
  CPU: 0 UID: 0 PID: 65 Comm: kpktgend_0
  RIP: 0010:mod_cur_headers+0x16f8/0x2840
  Call Trace:
   <TASK>
   pktgen_thread_worker+0x305a/0x6bc0
   kthread+0x2c6/0x3b0
   ret_from_fork+0x36e/0x5a0
   ret_from_fork_asm+0x1a/0x30
   </TASK>

Read cflows once at the start of mod_cur_headers(), pass the snapshot to
f_pick(), and use it for later flow-state decisions in the same packet.
Publish proc updates with WRITE_ONCE(). Flow selection then always uses a
nonzero count bounded by MAX_CFLOWS, while a concurrent update takes
effect on a later packet.

Fixes: 007a531b0a0c ("[PKTGEN]: Introduce sequential flows")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <redacted>
Signed-off-by: Qi Zhang <redacted>
---
 net/core/pktgen.c | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index ee64f3012321..631cb1f55f6d 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -1632,7 +1632,7 @@ static ssize_t pktgen_if_write(struct file *file,
 		if (value > MAX_CFLOWS)
 			value = MAX_CFLOWS;
 
-		pkt_dev->cflows = value;
+		WRITE_ONCE(pkt_dev->cflows, value);
 		sprintf(pg_result, "OK: flows=%u", pkt_dev->cflows);
Please use:
		sprintf(pg_result, "OK: flows=%u", value);

so that the user get consistent results across racing writes.

Also you need to add READ_ONCE() annotation to all `->cflows` accesses -
a few missed ones in pktgen_if_show().

/P
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help