Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!ut-sally!husc6!panda!genrad!decvax!tektronix!uw-beaver!ssc-vax!uvicctr!gduncan From: gduncan@uvicctr.UUCP (Gary Duncan) Newsgroups: net.bugs.4bsd Subject: possible truncated /etc/passwd file Message-ID: <185@uvicctr.UUCP> Date: Thu, 11-Sep-86 19:00:49 EDT Article-I.D.: uvicctr.185 Posted: Thu Sep 11 19:00:49 1986 Date-Received: Tue, 16-Sep-86 22:42:31 EDT Distribution: net Organization: University of Victoria, Victoria B.C. Canada Lines: 47 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);