Date: Thu, 5 Jul 2007 16:05:59 -0500 (CDT) From: Leif Pedersen <bilbo@hobbiton.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: bin/114341: lockf(1) utility is severely broken Message-ID: <20070705210559.31877130C7E@smaug.hobbiton.org> Resent-Message-ID: <200707052140.l65LeBAM022063@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 114341 >Category: bin >Synopsis: lockf(1) utility is severely broken >Confidential: no >Severity: critical >Priority: high >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Jul 05 21:40:10 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Leif Pedersen >Release: FreeBSD 6.2-RELEASE-p2 i386 >Organization: >Environment: System: FreeBSD legolas.hobbiton.org 6.2-RELEASE-p2 FreeBSD 6.2-RELEASE-p2 #0: Sun May 27 22:11:57 CDT 2007 bilbo@legolas.hobbiton.org:/tmp/work/usr/src/sys/HOBBITON_STANDARD i386 All arches. >Description: lockf(1) does not properly implement locking. The problem is that lockf calls open() with O_CREAT and O_EXLOCK, but open() does not implement creating the file and locking it atomically. Calling open in this way is the same as calling open without O_EXLOCK, then separately calling flock(). >How-To-Repeat: lockf will break under the following use case: - Alice executes lockf /tmp/test.lock foobar. - Bob executes lockf /tmp/test.lock foobar. - Alice finishes executing foobar (and lockf removes the lockfile). - Bob obtains the lock (but lockf forgets to create a lockfile to replace the removed one). - Charlie executes lockf /tmp/test.lock foobar. - Charlie immediately begins executing foobar, since there is no record of Bob's lock. - Bob and Charlie are now erroneously executing foobar at the same time. >Fix: To work around, always use the -k option to flock(1). To fix the problem, patch the code to check that the file exists after open() returns. For example: while(1) { lockfd = open(name, O_CREAT|O_RDONLY|O_EXLOCK, 0666); if(lockfd == -1) { ...abort } checkfd = open(name, O_RDONLY, 0); if(checkfd != -1) { // Successful lock. Continue execution. close(checkfd); break; } // Lock file was removed by a concurrent peer. Try again. if(errno != ENOENT) { close(lockfd); ...abort - almost can't happen } close(lockfd); } >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070705210559.31877130C7E>