Re: [PATCH net] net: pktgen: use a consistent flow count
Paolo Abeni <[email protected]>
| Newsgroups | org.kernel.vger.netdev,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
On 8/2/26 5:23 PM, Qi Zhang wrote: > From: Chengfeng Ye <[email protected]> > > 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: [email protected] > Signed-off-by: Chengfeng Ye <[email protected]> > Signed-off-by: Qi Zhang <[email protected]> > --- > 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