Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
sys/cnmac: read next RX buffer pointer before release
To:
OpenBSD tech <tech@openbsd.org>, visa@openbsd.org
Date:
Thu, 18 Jun 2026 11:02:36 +0200

Download raw body.

Thread
  • Kirill A. Korinsky:

    sys/cnmac: read next RX buffer pointer before release

tech@, Visa,

My ER-4 which I use as home's gw crashed some time ago with stacktrace:

ddb{0}> trace
cnmac_recv_mbuf+0x13c (77e060040f88a,1,980000000fd979f8,980000000fd979f4)  ra 0
xffffffff810f13a0 sp 0x980000000fd97990, sz 32
cnmac_recv+0x88 (77e060040f88a,1,980000000fd979f8,b14f8e2ae1694c1c)  ra 0xfffff
fff810eddb0 sp 0x980000000fd979b0, sz 144
cnmac_intr+0x100 (77e060040f88a,593aedd32134a2c6,980000000fd979f8,4)  ra 0xffff
ffff8124a06c sp 0x980000000fd97a40, sz 112
octciu_intr_bank+0x274 (77e060040f88a,593aedd32134a2c6,980000000fd979f8,47bf232
1b40c9360)  ra 0xffffffff8124976c sp 0x980000000fd97ab0, sz 160
octciu_intr0+0x94 (77e060040f88a,593aedd32134a2c6,57aacbc77ca5909c,47bf2321b40c
9360)  ra 0xffffffff811a0f68 sp 0x980000000fd97b50, sz 64
interrupt+0x170 (77e060040f88a,1da67593047e9497,57aacbc77ca5909c,47bf2321b40c93
60)  ra 0xffffffff813461f4 sp 0x980000000fd97b90, sz 64
k_intr+0xb4 (980000000fd97bf8,1da67593047e9497,57aacbc77ca5909c,ffffffff811e948
c)  ra 0x0 sp 0x980000000fd97bd0, sz 0
(KERNEL INTERRUPT)
cpu_idle_cycle_wait+0x4 (980000000fd97bf8,1da67593047e9497,57aacbc77ca5909c,fff
fffff811e948c)  ra 0xffffffff810a7ccc sp 0x980000000fd97d50, sz 0
sched_idle+0x314 (980000000fd97bf8,1da67593047e9497,57aacbc77ca5909c,ffffffff81
1e948c)  ra 0xffffffff811e95bc sp 0x980000000fd97d50, sz 96
proc_trampoline+0x1c (980000000fd97bf8,1da67593047e9497,57aacbc77ca5909c,ffffff
ff811e948c)  ra 0x0 sp 0x980000000fd97db0, sz 0
User-level: pid 7056
ddb{0}> 

I not completley sure that had happened, but here some thoughts that can fix
that, as blind shot, or it can be absolutley wrong.

The idea that in both RX drop and receive paths, copy the next WQE word
before the current packet buffer is returned to FPA or its hidden mbuf
pointer is cleared.

Returning the buffer first allows hardware to reuse it before the driver
has consumed the chained buffer pointer; that can corrupt word3 and
later fault in cnmac_recv_mbuf() while recovering the mbuf from pktbuf.

Thougths? Ok?

Index: sys/arch/octeon/dev/if_cnmac.c
===================================================================
RCS file: /home/cvs/src/sys/arch/octeon/dev/if_cnmac.c,v
diff -u -p -r1.90 if_cnmac.c
--- sys/arch/octeon/dev/if_cnmac.c	27 Apr 2026 16:54:49 -0000	1.90
+++ sys/arch/octeon/dev/if_cnmac.c	18 Jun 2026 01:23:19 -0000
@@ -722,12 +722,12 @@ cnmac_buf_free_work(struct cnmac_softc *
 		    PIP_WQE_WORD3_BACK_SHIFT;
 		pktbuf = (addr & ~(CACHELINESIZE - 1)) - back * CACHELINESIZE;
 
-		cn30xxfpa_store(pktbuf, OCTEON_POOL_NO_PKT,
-		    OCTEON_POOL_SIZE_PKT / CACHELINESIZE);
-
 		if (nbufs > 0)
 			memcpy(&word3, (void *)PHYS_TO_XKPHYS(addr -
 			    sizeof(word3), CCA_CACHED), sizeof(word3));
+
+		cn30xxfpa_store(pktbuf, OCTEON_POOL_NO_PKT,
+		    OCTEON_POOL_SIZE_PKT / CACHELINESIZE);
 	}
 
 	cn30xxfpa_buf_put_paddr(cnmac_fb_wqe, XKPHYS_TO_PHYS(work));
@@ -1244,6 +1244,9 @@ cnmac_recv_mbuf(struct cnmac_softc *sc, 
 		addr = word3 & PIP_WQE_WORD3_ADDR;
 		back = (word3 & PIP_WQE_WORD3_BACK) >> PIP_WQE_WORD3_BACK_SHIFT;
 		pktbuf = (addr & ~(CACHELINESIZE - 1)) - back * CACHELINESIZE;
+		if (i + 1 < nbufs)
+			memcpy(&word3, (void *)PHYS_TO_XKPHYS(addr -
+			    sizeof(word3), CCA_CACHED), sizeof(word3));
 		pm = (struct mbuf **)PHYS_TO_XKPHYS(pktbuf, CCA_CACHED) - 1;
 		m = *pm;
 		*pm = NULL;
@@ -1276,10 +1279,6 @@ cnmac_recv_mbuf(struct cnmac_softc *sc, 
 			mprev->m_next = m;
 		}
 		mprev = m;
-
-		if (i + 1 < nbufs)
-			memcpy(&word3, (void *)PHYS_TO_XKPHYS(addr -
-			    sizeof(word3), CCA_CACHED), sizeof(word3));
 	}
 
 	m0->m_pkthdr.len = total;


-- 
wbr, Kirill