[net.bugs.4bsd] Broadcast ICMP ECHO crash fix

rusty@sun.uucp (Russel Sandberg) (04/03/84)

Subject: broadcast ICMP ECHO system crash fix
Index:	sys/netinet/if_ether.c 4.2BSD

Description:
	Sending a broadcast ICMP ECHO packet on an ether net with lots of
	hosts can cause the system to crash due to duplicate mbufs.
Repeat-By:
	Send an ICMP ECHO packet on an ethernet with >50 hosts.
Fix:
	The ethernet driver (if_ec.c) call arpresolve to get an ethernet
	address from an arpanet address.  Arpresolve normaly returns 1 for
	success and 0 for failure.  However, when arpresolve sees a packet
	addressed to itself it calls the loopback driver (if_loop.c) and
	returns the result of that call.  Loopback returns 0 for success and
	errno for error.  When the loopback call works everything is ok
	because arpresolve then returns a 0, if_ec interprets this as an
	error and returns immediately.  But when the loopback driver fails
	(due to ip input queue full) it returns ENOBUFS and frees the mbuf
	chain.  Arpresolve returns the error to if_ec which interprets it as
	success and sends out the packet.  When it  has been sent if_ec frees
	the same mbuf chain.

	The real fix would be to get the call to looutput out of arpresolve.
	This is a complete crock, the packet gets sent as a side effect of
	resolving the address?  It's no wonder a bug turned up here.

	Here is a diff -c which gives a quick and dirty fix (ignore line 
	numbers).
	*** if_ether.c		Sun Aug 28 01:30:48 1983
	--- /if_ether.c.new	Mon Apr  2 15:18:54 1984
	***************
	*** 202,208
		    ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) {
			sin.sin_family = AF_INET;
			sin.sin_addr = *destip;
	! 		return (looutput(&loif, m, (struct sockaddr *)&sin));
		}
		if ((ifp->if_flags & IFF_NOARP) || lna >= oldmap) {
			bcopy((caddr_t)ac->ac_enaddr, (caddr_t)desten, 3);

	--- 149,156 -----
		    ((struct sockaddr_in *)&ifp->if_addr)-> sin_addr.s_addr) {
			sin.sin_family = AF_INET;
			sin.sin_addr = *destip;
	! 		(void) looutput(&loif, m, (struct sockaddr *)&sin);
	! 		return (0);
		}
	  #ifdef IPENADDR
		if (destip->s_net == 0) {	/* real IP address unknown */