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 */