Date: Wed, 27 May 1998 13:02:01 -0700 (PDT) From: Craig Spannring <cts@internetcds.com> To: freebsd-hackers@FreeBSD.ORG Subject: Race conditions in pw Message-ID: <199805272002.NAA18714@bangkok.office.cdsnet.net>
next in thread | raw e-mail | index | archive | help
vipw, chpass and passwd all lock the /etc/master.passwd file for the entire time they run. pw tries not to hold the lock the entire time. Specifically it does not have the file locked when it calls pwd_mkdb. This causes some race conditions since multiple instances of pwd_mkdb can run at the same time. I think pw should take a pessimistic approach and keep the /etc/master.passwd file locked the entire time just like passwd, vipw and chpass. My quick fix for pw opens /etc/master.passwd in main() with the O_EXLOCK flag in pw.c and doesn't close the file descriptor. I also had to make sure that fileupdate() in fileupd.c does not try to lock the /etc/master.passwd file. I tried to contact David L. Nugent, <davidn@blaze.net.au> last week but I have heard back from him yet. The following perl script will demonstrate the race condition. It forks 10 copies of itself and each one tries to create and delete 100 users. With a fixed version of pw there will be no error messages from pwd_mkdb and it will delete all of the new accounts before it finishes. With the current version of pw you wind up with a large number of accounts that aren't deleted because of the race condition and a large number of messages from pwd_mkdb such as- pwd_mkdb: /etc/pwd.db.tmp: File exists pwd_mkdb: /etc/pwd.db.tmp to /etc/pwd.db: No such file or directory pwd_mkdb: /etc/pwd.db.tmp: No such file or directory pwd_mkdb: /etc/spwd.db.tmp: File exists #!/usr/local/bin/perl -w # # # Demonstrate pw glitch that occurs when multiple instances of pw run # at the same time. # use strict 'vars'; use strict 'subs'; use diagnostics; use diagnostics -verbose; enable diagnostics; my $a; my $b; my $i; my $notAdded = 0; my $notDeleted = 0; my $wasAdded = 0; my $pwAddFailures = 0; my $pwDelFailures = 0; my $PW="/usr/sbin/pw"; for($i=0; $i<10; $i++) { my $rc = fork(); if ($rc == -1) { print STDERR "Couldn't fork\n"; exit(1); } elsif ($rc == 0) { next; } else { foreach $a ('0'..'9') { foreach $b ('0'..'9') { my $username = "u$a$b$$"; my $cmd = "$PW useradd $username -d /tmp/$a/$b/$username"; mkdir("/tmp/$a", 0755); mkdir("/tmp/$a/$b", 0755); print "system($cmd);\n"; system($cmd)==0 || $pwAddFailures++; if (!defined(getpwnam($username))) { $notAdded++; $wasAdded=1; } else { $wasAdded=1; } $cmd = "$PW userdel $username"; print "system($cmd);\n"; system($cmd)==0 || $pwDelFailures++; if ($wasAdded && defined(getpwnam($username))) { $notDeleted++; } } } open (STATUS, ">/tmp/status.$$"); print STATUS "'pw adduser' recorded $pwAddFailures failures.\n"; print STATUS "'pw deluser' recorded $pwDelFailures failures.\n"; print STATUS "$notAdded accounts weren't added, $notDeleted accounts weren't deleted\n"; print STATUS "$notAdded accounts weren't added, $notDeleted accounts weren't deleted\n"; } } -- ======================================================================= Life is short. | Craig Spannring Ski hard, Bike fast. | cts@internetcds.com --------------------------------+------------------------------------ Any sufficiently perverted technology is indistinguishable from Perl. ======================================================================= To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805272002.NAA18714>