loverso@encore.UUCP (John LoVerso) (11/17/87)
Index: etc/comsat.c 4.3BSD +FIX
Description:
Comsat doesn't dereference a NULL pointer, but instead decrements
it by sizeof(struct utmp) and then dereferences that.
Comsat keeps a cached copy of /etc/utmp in malloc'd space. If
no-one has logged in since the machine was booted, /etc/utmp
will be length 0 and so no space will be malloc'd, leaving the
pointer `utmp' NULL. When there is an incoming message that
mail has been delivered, mailfor() gets called, and does the
following to step thru the utmp array:
register struct utmp *utp = &utmp[nutmp];
while (--utp >= utmp)
{ dereference utp }
A struct utmp is 36 bytes, and so --utp ends being 0xffffffdc.
On a VAX using the 4.3 C compiler, the comparison is done with
a "cmpl", which I think is a signed compare (I don't have a VAX
arch handbook handy). This means the expression in the while
will return false, and its body never get executed. But, both
the Sun3.4 C compiler and one used on a Multimax use unsigned
compares for pointers, allowing the expression in the while to
eval to true. The resulting dereference of utp produces a SEGV.
Of course, if comsat does dump core, inetd will start it back
up again the next time mail gets delivered.
Repeat-By:
Reboot your machine and then send mail from another host on the network
before anybody at all logs in (while /etc/utmp still has a length of 0).
Comsat should drop a core in /usr/spool/mail.
Fix:
Prevent mailfor() from being called when no-one is logged in.
*** comsat.c_orig Thu Nov 12 15:14:09 1987
--- comsat.c Thu Nov 12 15:08:15 1987
***************
*** 91,96 ****
--- 91,98 ----
errno = 0;
continue;
}
+ if (nutmp == 0) /* no users (yet) */
+ continue;
sigblock(sigmask(SIGALRM));
msgbuf[cc] = 0;
lastmsgtime = time(0);
--
John Robert LoVerso, Encore Computer Corp
encore!loverso, loverso@multimax.arpa