gww@marduk.UUCP (Gary Winiger) (09/05/87)
Subject: Unbuffered iob's can conflict with longjmp +Half Fix
Index: libc/stdio/fprintf.c 4.3BSD
Index: usr.bin/uucp/cico.c 4.3BSD +Fix
Description:
Unbuffered iob's, in this case stderr, can conflict with longjmp.
The 4.3 optimization of fprintf(3) changes unbuffered iob's to buffered,
allocates a line buffer on the stack, calls _doprnt(), then resets the
iob to be unbuffered.
If a process gets a signal during the window when the iob has been
set to buffered and then longjmps, the iob is left pointing to an
invalid area on the stack. Subsequently more procedures may be called
that cause this invalid area to be used when this happens and fprintf
is called again for this iob, it will see it as buffered and just
call _doprnt(). The buffer pointers are no longer valid, and can
cause strange results, in particular, NULL pointer dereferences.
Repeat-By:
Run cico with debugging on at a high level with the output comming
to a slow device like your terminal. Be lucky enough to get an alarm
that causes a longjmp. The next fprintf(stderr) is likely to take
a nose dive.
Fix:
I don't offer any fix to fprintf(3) because I agree with the desirabilty
of the optimization. I offer the following advice: DON'T USE
UNBUFFERED FILES WITH FPRINTF IF YOU ALSO CATCH SIGNALS AND LONGJMP!
The attached code solves this problem at Elxsi for UUCP/cico.
Gary..
{ucbvax!sun,lll-lcc!lll-tis,amdahl!altos86,bridge2}!elxsi!gww
--------- cut --------- snip --------- :.,$w diff -------------
*** /tmp/,RCSt1000796 Wed Jul 1 15:16:51 1987
--- /tmp/,RCSt2000796 Wed Jul 1 15:16:55 1987
***************
*** 1,11 ****
/*
* $Log: cico.c,v $
* Revision 1.1 87/06/23 16:57:59 gww
* Initial revision
*
*/
#ifndef lint
! static char *ERcsId = "$Header: cico.c,v 1.1 87/06/23 16:57:59 gww Exp $ ENIX BSD";
static char sccsid[] = "@(#)cico.c 5.14 (Berkeley) 4/14/86";
#endif
--- 1,20 ----
/*
* $Log: cico.c,v $
+ * Revision 1.2 87/07/01 15:02:11 gww
+ * Make stderr line buffered. It probably should be anyway, but it is possible
+ * to be outputing a debugging line, get an alarm and longjmp to in the middle
+ * of the fprintf(stderr,... thus leaving the _iob[stderr] with bogus pointers
+ * into the stack and the line buffered flag set (due to 4.3 fprintf
+ * optimization of unbuffered _iob's), a subsequent fprintf(stderr, ... could
+ * blow up with a NULL pointer reference if intervening calls wrote over where
+ * the line buffer had been allocated on the stack.
+ *
* Revision 1.1 87/06/23 16:57:59 gww
* Initial revision
*
*/
#ifndef lint
! static char *ERcsId = "$Header: cico.c,v 1.2 87/07/01 15:02:11 gww Exp $ ENIX BSD";
static char sccsid[] = "@(#)cico.c 5.14 (Berkeley) 4/14/86";
#endif
***************
*** 120,126 ****
uucpname(Myname);
ASSERT(ret == 0, "BAD UID", CNULL, ret);
! setbuf (stderr, CNULL);
rflags[0] = '\0';
umask(WFMASK);
--- 129,135 ----
uucpname(Myname);
ASSERT(ret == 0, "BAD UID", CNULL, ret);
! setlinebuf(stderr);
rflags[0] = '\0';
umask(WFMASK);
***************
*** 870,876 ****
assert("FAILED RMTDEBUG FILE OPEN:", buf, errno);
cleanup(1);
}
! setbuf(stderr, CNULL);
auditopen = 1;
}
--- 879,885 ----
assert("FAILED RMTDEBUG FILE OPEN:", buf, errno);
cleanup(1);
}
! setlinebuf(stderr);
auditopen = 1;
}