Index | Thread | Search

From:
Vitaliy Makkoveev <mvs@openbsd.org>
Subject:
Re: socket splicing loop counter
To:
Alexander Bluhm <bluhm@openbsd.org>
Cc:
tech@openbsd.org
Date:
Sun, 22 Feb 2026 08:00:10 +0300

Download raw body.

Thread
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);
>