Hi,

There exists a race when a process is trying to read from a spliced
socket.  soreceive() releases splsoftnet for uiomove().  In that
moment, somove() can pull the mbuf from the receive buffer.  After
that, soreceive will remove the mbuf again.  The corrupt length
accounting will result in a panic.

The fix is to block read calls in soreceive() until splicing has
been finished.

ok?

bluhm


Index: sys/kern/uipc_socket.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.86
diff -u -p -r1.86 uipc_socket.c
--- sys/kern/uipc_socket.c      28 Feb 2011 16:29:42 -0000      1.86
+++ sys/kern/uipc_socket.c      11 Mar 2011 21:52:02 -0000
@@ -612,6 +612,10 @@ restart:
        s = splsoftnet();
 
        m = so->so_rcv.sb_mb;
+#ifdef SOCKET_SPLICE
+       if (so->so_splice)
+               m = NULL;
+#endif /* SOCKET_SPLICE */
        /*
         * If we have less data than requested, block awaiting more
         * (subject to any timeout) if:
@@ -630,6 +634,9 @@ restart:
            m->m_nextpkt == NULL && (pr->pr_flags & PR_ATOMIC) == 0)) {
 #ifdef DIAGNOSTIC
                if (m == NULL && so->so_rcv.sb_cc)
+#ifdef SOCKET_SPLICE
+                   if (so->so_splice == NULL)
+#endif /* SOCKET_SPLICE */
                        panic("receive 1");
 #endif
                if (so->so_error) {
Index: share/man/man9/sosplice.9
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/share/man/man9/sosplice.9,v
retrieving revision 1.1
diff -u -p -r1.1 sosplice.9
--- share/man/man9/sosplice.9   8 Mar 2011 00:13:41 -0000       1.1
+++ share/man/man9/sosplice.9   11 Mar 2011 21:46:42 -0000
@@ -152,8 +152,10 @@ and
 will call
 .Fn somove
 to trigger the transfer when new data or buffer space is available.
-While socket splicing is active, the read wakeup will not be delivered
-to the source file descriptor.
+While socket splicing is active, any
+.Xr read 2
+from the source socket will block and the wakeup will not be delivered
+to the file descriptor.
 A read event is signaled to user-land after dissolving.
 .Sh RETURN VALUES
 .Fn sosplice

Reply via email to