From: sms@WLV.IIPO.GTEGSC.COM (Steven M. Schultz)
Subject: sendmail stack underflow  + fix (#105)
Organization: GTE Government Systems
Date: Thu, 28 Jan 93 05:14:20 GMT

Subject: sendmail stack underflow  + fix (#105)
Index:	usr.lib/sendmail/src/daemon.c 2.11BSD

Description:
	When 'sendmail' is linked with the resolver(5) routines there
	is a flow of execution which causes the stack pointer (sp) to
	be decremented into an invalid region in the adjacent data space.

Repeat-By:
	Difficult to repeat because much depends on exactly how large
	sendmail's D space is (if there is room to expand the stack
	the problem will not occur), how complex the sendmail.cf file
	is, etc.  If your sendmail periodically dumps core and the
	stack trace looks something like this then you're experiencing
	the problem and this fix will help.  All numbers are octal, the
	number at the left is the current stack pointer value and the
	actual arguments are not given.  The 'sp' value at the time
	sendmail crashed was 157556:

	160646 _res_sen(...)
	162676 _rs_qry(...)
	163732 _rs_qryd(...)
	163776 _res_sea(...)
	166020 _gethbyn(...)
	166444 _maphost(...)
	167712 _rewrite(...)
	170444 _remoten(...)
	171416 _commaiz(...)
	174052 L162(...) - not sure why this came out with a local name...
	174052 _smtpdat(...)
	175154 _deliver(...)
	175406 _sendall(...)
	176402 _smtp(...)
	177402 _main()

	How does 'sp' get pushed into the data segment and why does it
	cause a crash of sendmail?  The data segment has expanded into
	into seg6 (virtual range 140000-157776) but the entire 8kb has 
	not been allocated, for example the last valid data address 
	might be 155000 - the gap between end of data and 160000 is a
	"noman's land"

	In res_send (one of the resolver routines) the stack pointer
	is 160646 and res_send allocates (yet another) 512 byte buffer
	(plus a couple more local variables) on the stack which causes 'sp' 
	to be decremented to 157646.  This is above the last valid
	data address (155000) and below 160000 (last allocated stack
	space), thus the first reference to where sp points will cause
	a fault.

	Sendmail's habit of allocating 512 and 1kb buffers at almost
	every level of function call is the main culprit (the resolver
	routines are almost as bad).

Fix:
	The fix below reduces sendmail's stack requirement by 256 bytes
	which has proven to be sufficient to prevent the program from
	crashing.  Not sure why the address string was copied when earlier
	references to bracketed dotted quads were handled by simply
	poking a zero into the string and restoring it after 'inet_addr'
	was finished.

==========================cut here=============================
*** /usr/src/usr.lib/sendmail/src/daemon.c.old	Wed Feb 10 15:26:12 1988
--- /usr/src/usr.lib/sendmail/src/daemon.c	Wed Jan 27 20:26:37 1993
***************
*** 14,20 ****
  
  # ifndef DAEMON
  #if !defined(lint) && !defined(NOSCCS)
! static char	SccsId[] = "@(#)daemon.c	5.19 (Berkeley) 5/6/86	(w/o daemon mode)";
  # endif
  # else
  
--- 14,20 ----
  
  # ifndef DAEMON
  #if !defined(lint) && !defined(NOSCCS)
! static char	SccsId[] = "@(#)daemon.c	5.20 (2.11BSD) 1/26/93	(w/o daemon mode)";
  # endif
  # else
  
***************
*** 25,31 ****
  # include <sys/resource.h>
  
  #if !defined(lint) && !defined(NOSCCS)
! static char	SccsId[] = "@(#)daemon.c	5.19 (Berkeley) 5/6/86 (with daemon mode)";
  # endif
  
  /*
--- 25,31 ----
  # include <sys/resource.h>
  
  #if !defined(lint) && !defined(NOSCCS)
! static char	SccsId[] = "@(#)daemon.c	5.20 (2.11BSD) 1/26/93 (with daemon mode)";
  # endif
  
  /*
***************
*** 499,507 ****
  
  	/*
  	**  If first character is a bracket, then it is an address
! 	**  lookup.  Address is copied into a temporary buffer to
! 	**  strip the brackets and to preserve hbuf if address is
! 	**  unknown.
  	*/
  
  	if (*hbuf == '[')
--- 499,505 ----
  
  	/*
  	**  If first character is a bracket, then it is an address
! 	**  lookup.
  	*/
  
  	if (*hbuf == '[')
***************
*** 508,520 ****
  	{
  		extern struct hostent *gethostbyaddr();
  		u_long in_addr;
! 		char ptr[256];
! 		char *bptr;
  
! 		(void) strcpy(ptr, hbuf);
! 		bptr = index(ptr,']');
  		*bptr = '\0';
! 		in_addr = inet_addr(&ptr[1]);
  		hp = gethostbyaddr((char *) &in_addr, sizeof(struct in_addr), AF_INET);
  		if (hp == NULL)
  			return;
--- 506,517 ----
  	{
  		extern struct hostent *gethostbyaddr();
  		u_long in_addr;
! 		register char *bptr;
  
! 		bptr = index(hbuf,']');
  		*bptr = '\0';
! 		in_addr = inet_addr(&hbuf[1]);
! 		*bptr = ']';
  		hp = gethostbyaddr((char *) &in_addr, sizeof(struct in_addr), AF_INET);
  		if (hp == NULL)
  			return;