From 10fabdd075df1076f0d694cf99ddee838d0d1da7 Mon Sep 17 00:00:00 2001 From: bluhm Date: Thu, 11 Jun 2026 19:21:51 +0000 Subject: [PATCH] Fix race during socket unsplicing. Problem was that splicing holds the socket lock when it writes so_sp, but unsplicing does not when it reads so_sp. So it may get the new pointer, but PR_ZERO is not visible due to reordering. Then so->so_sp->ssp_socket is garbage. Crash happend on octeon/mips64 during regress/sys/netinet/udpthread test run-unsplice. When creating a splice from socket 1 to socket 2, kernel holds socket buffer lock on so1->so_rcv and so2->so_snd and socket lock on both while installing so_sp on so1 and so2. Concurrent sosplice() on socket 2 has the opposite order, we hold sblock on so2->so_rcv, sblock on so1->so_snd and solock on both sockets. The unsplice thread of the source socket did hold sblock on so->so_rcv only. So we did lockless so_sp check while concurrent sosplice() thread installs so_sp on the same socket as drain, holding sblock on so->so_snd. Grabbing sblock on both so->so_srv and so->so_snd fixes the crash. with and OK mvs@ --- sys/kern/uipc_socket.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 2e5934be756..7df1c7fbea1 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_socket.c,v 1.388 2026/02/22 21:30:58 bluhm Exp $ */ +/* $OpenBSD: uipc_socket.c,v 1.389 2026/06/11 19:21:51 bluhm Exp $ */ /* $NetBSD: uipc_socket.c,v 1.21 1996/02/04 02:17:52 christos Exp $ */ /* @@ -1323,10 +1323,15 @@ sosplice(struct socket *so, int fd, off_t max, struct timeval *tv) if (fd < 0) { if ((error = sblock(&so->so_rcv, SBL_WAIT)) != 0) return (error); + if ((error = sblock(&so->so_snd, SBL_WAIT)) != 0) { + sbunlock(&so->so_rcv); + return (error); + } if (so->so_sp && so->so_sp->ssp_socket) sounsplice(so, so->so_sp->ssp_socket, 0); else error = EPROTO; + sbunlock(&so->so_snd); sbunlock(&so->so_rcv); return (error); }