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; }