From: Vitaliy Makkoveev Subject: Re: socket splicing loop counter To: Alexander Bluhm Cc: tech@openbsd.org Date: Sun, 22 Feb 2026 08:00:10 +0300 On Fri, Feb 20, 2026 at 06:47:31PM +0100, Alexander Bluhm wrote: > Hi, > > To avoid endless splicing loops, the mbuf's lifetime is limited by > the ph_loopcnt counter. Each time somove() compares the value to > a maximum and increments. > > After that, in the unlikely case that the drain buffer is full, the > mbuf stays in the source buffer. Then it is incremented again when > more data arrives and somove() is called. Eventually the maxiumm > could be reached and splicing dissolved with ELOOP. This was not > intended for mbufs which never moved, we want to count the moves. > > Avoid the race and increment just before sending the mbuf out to > the new buffer. > > ok? > ok mvs > bluhm > > Index: kern/uipc_socket.c > =================================================================== > RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket.c,v > diff -u -p -r1.387 uipc_socket.c > --- kern/uipc_socket.c 21 Jan 2026 10:18:20 -0000 1.387 > +++ kern/uipc_socket.c 20 Feb 2026 15:40:27 -0000 > @@ -1592,12 +1592,9 @@ somove(struct socket *so, int wait) > /* > * By splicing sockets connected to localhost, userland might create a > * loop. Dissolve splicing with error if loop is detected by counter. > - * > - * If we deal with looped broadcast/multicast packet we bail out with > - * no error to suppress splice termination. > */ > if ((m->m_flags & M_PKTHDR) && > - ((m->m_pkthdr.ph_loopcnt++ >= M_MAXLOOP) || > + ((m->m_pkthdr.ph_loopcnt >= M_MAXLOOP) || > ((m->m_flags & M_LOOP) && (m->m_flags & (M_BCAST|M_MCAST))))) { > error = ELOOP; > goto release; > @@ -1737,6 +1734,8 @@ somove(struct socket *so, int wait) > } else if (oobmark) { > o = m_split(m, oobmark, wait); > if (o) { > + if (m->m_flags & M_PKTHDR) > + m->m_pkthdr.ph_loopcnt++; > solock_shared(sosp); > error = pru_send(sosp, m, NULL, NULL); > sounlock_shared(sosp); > @@ -1793,6 +1792,8 @@ somove(struct socket *so, int wait) > > mtx_leave(&sosp->so_snd.sb_mtx); > mtx_leave(&so->so_rcv.sb_mtx); > + if (m->m_flags & M_PKTHDR) > + m->m_pkthdr.ph_loopcnt++; > solock_shared(sosp); > error = pru_send(sosp, m, NULL, NULL); > sounlock_shared(sosp); >