Subject: kern/35962: sokcet leak when socket on the pend queue (so_q) rcv'd a RST
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: None <rmenner@equallogic.com>
List: netbsd-bugs
Date: 03/09/2007 14:40:00
>Number:         35962
>Category:       kern
>Synopsis:       sokcet leak when socket  on the pend queue (so_q) rcv'd a RST
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Mar 09 14:40:00 +0000 2007
>Originator:     Ron Menner
>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.M
PACPI 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* there is no so_pcb,  call sofree() which will free the socket since it is off th so_q.  Return ECONNRESET to the application.