Download raw body.
socket splicing loop counter
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?
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);
socket splicing loop counter