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 #if !defined(lint) && !defined(NOSCCS) ! static char SccsId[] = "@(#)daemon.c 5.19 (Berkeley) 5/6/86 (with daemon mode)"; # endif /* --- 25,31 ---- # include #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;