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