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