Subject: kern/35963: socket leak
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <rmenner@equallogic.com>
List: netbsd-bugs
Date: 03/09/2007 15:20:01
>Number:         35963
>Category:       kern
>Synopsis:       Socket leak when RST is received before application issues accept
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Mar 09 15:20:00 +0000 2007
>Originator:     rmenner@equallogic.com
>Release:        NetBSD 2.1
>Organization:
   Equallogic Inc.
>Environment:
System: NetBSD ronnetbsd 2.1 NetBSD 2.1 (GENERIC.MPACPI) #3: Mon Nov 21 18:29:34 EST 2005 root@nx01:/var/tmp/netbsd-2.1/i386/obj/sys/arch/i386/compile/GENERIC.MPACPI i386
Architecture: i386
Machine: i386
>Description:
         In the V4.4 BSD code the kernel handled the situation where a socket on the accept pending queue (so_q)
         was disconnected (via a TCP RST).  This was accomplished when in_pcbdetach() was called,  It freed both 
         the socket( via calling sofree) and the in_pcb.  However, a change was made in sofree() which will not 
         free the socket if it is on the so_q.  This change was made to sofree() so that when select() returned
         the listener socket was readable the accept call will not block (for possible an excessive long time) 
         due to no sockets on the so_q of the listening socket.  Moreover, since the socket is marked as 
         SS_ISDISCONNECTED in tcp_close(), soaccept() will not go down to the protocol (via the tcp_usrreq)
         and will return to sys_accept() which does not free the socket.
>How-To-Repeat:
         the program, nmap, which is part of the Linux distribution completes the three
         way TCP handshake then immediately send a RST.  The following script run on 
         linux will cause a socket leak:

               while [ true ]
               do
                  nmap -st <Ipaddress of NetBSD> -p <any port which has a listener>
               done
         	
>Fix:
          Possible fix:
          Have in_pcbdetach() check if the socket in on th so_q
          If so, clear SS_ISDISCONNECTED.
          When the PRU_ACCEPT is issued to the protocol *and* the is no so_pcb,
          call sofree() which will free the socket since it is off th so_q.