Synopsis: Fixes select(2)/accept(2) race condition which permits DoS.
NetBSD versions: 1.0 - 1.3.3.

Index: kern/uipc_socket.c
===================================================================
RCS file: /cvsroot/src/sys/kern/uipc_socket.c,v
retrieving revision 1.29.4.1
diff -c -2 -r1.29.4.1 uipc_socket.c
*** uipc_socket.c       1998/01/30 19:24:12     1.29.4.1
--- uipc_socket.c       1999/01/21 22:09:56
***************
*** 147,153 ****
               return;
       if (so->so_head) {
!               if (!soqremque(so, 0) && !soqremque(so, 1))
!                       panic("sofree dq");
!               so->so_head = 0;
       }
       sbrelease(&so->so_snd);
--- 147,157 ----
               return;
       if (so->so_head) {
!               /*
!                * We must not decommission a socket that's on the accept(2)
!                * queue.  If we do, then accept(2) may hang after select(2)
!                * indicated that the listening socket was ready.
!                */
!               if (!soqremque(so, 0))
!                       return;
       }
       sbrelease(&so->so_snd);
***************
*** 165,176 ****
       register struct socket *so;
 {
       int s = splsoftnet();           /* conservative */
       int error = 0;

       if (so->so_options & SO_ACCEPTCONN) {
!               while (so->so_q0.tqh_first)
!                       (void) soabort(so->so_q0.tqh_first);
!               while (so->so_q.tqh_first)
!                       (void) soabort(so->so_q.tqh_first);
       }
       if (so->so_pcb == 0)
--- 169,185 ----
       register struct socket *so;
 {
+       struct socket *so2;
       int s = splsoftnet();           /* conservative */
       int error = 0;

       if (so->so_options & SO_ACCEPTCONN) {
!               while ((so2 = so->so_q0.tqh_first) != 0) {
!                       (void) soqremque(so2, 0);
!                       (void) soabort(so2);
!               }
!               while ((so2 = so->so_q.tqh_first) != 0) {
!                       (void) soqremque(so2, 1);
!                       (void) soabort(so2);
!               }
       }
       if (so->so_pcb == 0)
***************
*** 235,240 ****
               panic("soaccept: !NOFDREF");
       so->so_state &= ~SS_NOFDREF;
!       error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, (struct mbuf *)0,
!           nam, (struct mbuf *)0, (struct proc *)0);
       splx(s);
       return (error);
--- 244,252 ----
               panic("soaccept: !NOFDREF");
       so->so_state &= ~SS_NOFDREF;
!       if ((so->so_state & SS_ISDISCONNECTED) == 0)
!               error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
!                   (struct mbuf *)0, nam, (struct mbuf *)0, (struct proc *)0);
!       else
!               error = 0;
       splx(s);
       return (error);
Index: kern/uipc_socket2.c
===================================================================
RCS file: /cvsroot/src/sys/kern/uipc_socket2.c,v
retrieving revision 1.21.2.1
diff -c -2 -r1.21.2.1 uipc_socket2.c
*** uipc_socket2.c      1998/01/29 10:42:13     1.21.2.1
--- uipc_socket2.c      1999/01/21 22:09:56
***************
*** 135,139 ****

       so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
!       so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
       wakeup((caddr_t)&so->so_timeo);
       sowwakeup(so);
--- 135,139 ----

       so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
!       so->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
       wakeup((caddr_t)&so->so_timeo);
       sowwakeup(so);
Index: sys/socketvar.h
===================================================================
RCS file: /cvsroot/src/sys/sys/socketvar.h,v
retrieving revision 1.25.2.1
diff -c -2 -r1.25.2.1 socketvar.h
*** socketvar.h 1998/01/29 10:47:24     1.25.2.1
--- socketvar.h 1999/01/21 22:09:56
***************
*** 117,120 ****
--- 117,121 ----
 #define       SS_CANTRCVMORE          0x020   /* can't receive more data from peer */
 #define       SS_RCVATMARK            0x040   /* at mark on input */
+ #define       SS_ISDISCONNECTED       0x800   /* socket disconnected from peer */

 #define       SS_NBIO                 0x080   /* non-blocking ops */