Subject: kern/3857: Problem with ephemeral port shortage in in_pcbbind() and in_pcbconnect()
To: None <gnats-bugs@gnats.netbsd.org>
From: None <koji@math.human.nagoya-u.ac.jp>
List: netbsd-bugs
Date: 07/13/1997 14:58:50
>Number:         3857
>Category:       kern
>Synopsis:       Problem with ephemeral port shortage in in_pcbbind() and in_pcbconnect()
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Jul 13 04:20:02 1997
>Last-Modified:
>Originator:     Koji Imada - je4owb/2
>Organization:
Mathematics Group of Graduate School of Human
	Infomatics, Nagoya University, Japan.
>Release:        970705
>Environment:
	
System: NetBSD bimota 1.2G NetBSD 1.2G (BIMOTA) #: Wed Jul 2 01:36:36 JST 1997 koji@ducati:/mnt2/NetBSD/work/src-ufs-mod/sys/arch/i386/compile/BIMOTA i386


>Description:
	Current in_pcbbind() returns EAGAIN if ephemeral port is not
	available. But in_pcbbind() set inp->inp_laddr when nam != 0.

	Because of non-null inp->inp_laddr when in_pcbbind() returns
	EAGAIN, subsequent in_pcbbind() call never succeeds.

	And in_pcbconnect() doesn't assumes failure of in_pcbbind()
	with null argument. This could cause binding local port 0.
>How-To-Repeat:
	If all ephemeral port are exhausted, in_pcbconnect() will bind 
	local port 0 and in_pcbbind() with 0 port and non-null address 
	will return EAGAIN and subsequent call will never succeeds.
>Fix:
	Apply following patch.

Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /mnt2/NetBSD/cvsroot/netbsd/sys/netinet/in_pcb.c,v
retrieving revision 1.1.1.2
diff -u -r1.1.1.2 in_pcb.c
--- in_pcb.c	1997/04/01 07:17:18	1.1.1.2
+++ in_pcb.c	1997/07/13 05:38:37
@@ -184,6 +184,8 @@
 			if (!in_pcblookup_port(table, inp->inp_laddr,
 			    htons(lport), wild))
 				goto found;
+		if (!in_nullhost(inp->inp_laddr))
+			inp->inp_laddr = INADDR_ANY;
 		return (EAGAIN);
 	found:
 		table->inpt_lastport = lport;
@@ -314,9 +316,11 @@
 	    inp->inp_lport) != 0)
 		return (EADDRINUSE);
 	if (in_nullhost(inp->inp_laddr)) {
-		if (inp->inp_lport == 0)
-			(void)in_pcbbind(inp, (struct mbuf *)0,
-			    (struct proc *)0);
+		/* now in_pcbbind() may return EAGAIN... */
+		if (inp->inp_lport == 0 &&
+		    in_pcbbind(inp, (struct mbuf *)0,
+			       (struct proc *)0) == EAGAIN)
+			return (EAGAIN);
 		inp->inp_laddr = ifaddr->sin_addr;
 	}
 	inp->inp_faddr = sin->sin_addr;
>Audit-Trail:
>Unformatted: