[net.bugs.4bsd] possible truncated /etc/passwd file

gduncan@uvicctr.UUCP (Gary Duncan) (09/12/86)

Index:	bin/passwd.c 4.2BSD

Description:
	The precautions taken by the passwd program (and also the ucb/chsh,
	ucb/chfn programs) to prevent multiple update trashing of the passwd
	file are not adequate enough.  (I believe the vipw program is fine
	though).  The program works by creating a temporary copy of the
	updated passwd file by opening /etc/ptmp in exclusive-use mode then
	copying and modifying entries from the original.  No problem so far.
	The program then:
		1. renames the temporary file to /etc/passwd
		2. closes the stream pointer for the file.
	Unfortunately the exclusive-use mode is lost on rename before the
	stream buffers have been flushed.  If a process switch occurs between
	#1 and #2, another process could update the now truncated passwd file
	and havoc may ensue.  Corruption is very unlikely to occur in
	practice, but is possible.  Apologies if this has been posted before.
	Credit for finding this bug really belongs to Nigel Horspool.
Repeat-By:
	Invoke passwd twice and be very lucky (or unlucky depending on how
	you view it) with the timing of the processes.  You can simulate
	the bug by extending the time between the rename and fclose (ie. with
	a sleep or read from the terminal -- you may also want to remove
	the SIGSTP ignore signal so you can ^Z) and starting up a second
	passwd at this point.
Fix:
	Add a fflush(tf) immediately before the rename to flush the buffers.

*** passwd.c.old	Sun Jul 10 17:55:46 1983
--- passwd.c	Thu Sep 11 15:44:09 1986
***************
*** 166,171
  			pwd->pw_shell);
  	}
  	endpwent();
  	if (rename(temp, passwd) < 0) {
  		fprintf(stderr, "passwd: "); perror("rename");
  		unlink(temp);

--- 166,172 -----
  			pwd->pw_shell);
  	}
  	endpwent();
+ 	fflush(tf);
  	if (rename(temp, passwd) < 0) {
  		fprintf(stderr, "passwd: "); perror("rename");
  		unlink(temp);

chris@umcp-cs.UUCP (Chris Torek) (09/17/86)

In article <185@uvicctr.UUCP> gduncan@uvicctr.UUCP (Gary Duncan) writes:
>Description:
>	the passwd program ... works by creating a temporary copy of the
>	updated passwd file by opening /etc/ptmp in exclusive-use mode then
>	copying and modifying entries from the original.  No problem so far.
>	The program then:
>		1. renames the temporary file to /etc/passwd
>		2. closes the stream pointer for the file.
>	Unfortunately the exclusive-use mode is lost on rename before the
>	stream buffers have been flushed. ...
>Fix:
>	Add a fflush(tf) immediately before the rename to flush the buffers.
>
>  	endpwent();
>+ 	fflush(tf);
>  	if (rename(temp, passwd) < 0) {

It would also be a very good idea to check for ferror(tf), in case
the root file system is full.  Make that:

	endpwent();
	(void) fflush(tf);
	if (ferror(tf))
		/* do something */

This, too, is quite unlikely, but could have drastic consequences.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu