Hacking Linux Exposed





previous article
next article
Linux file locking mechanisms - Flock, Lockf, and Fcntl
By Bri Hatch.

Summary: Multitasking operating systems can be prone to race conditions, but implementing proper file locking routines can prevent programming mistakes.

Ever had two processes attempt to access the same file at the same time? Unlike some older PC operating systems, Linux doesn't prevent this in any way. The Unix philosophy is to grant access to a file (assuming file permissions permit it) to an unlimited number of process.

This can easily lead to nasty problems. Say you had two mail clients running at the same time, and both tried to rewrite /var/mail/USER at the same time that your mail delivery agent[1] tried to add some new emails to the end. If they weren't programmed to play friendly, the result could be a horribly corrupted mail spool and loss of email messages.[2]

As you can guess, file locking can be very important in security-critical code as well. The last thing you'd want to happen is for one process to be logging to a file and have a second version wipe it out, or a program that stores temporary authentication tokens erase entries used by a separate process, or have two programs that add users to /etc/passwd write at the same time, resulting in corrupted or passwordless accounts.

If you're programming in C, there are several locking functions available to you.

flock(fd, operation)
Locks or unlocks an entire file. Doesn't work on NFS mounted filesystems, unfortunately. Available operations are

LOCK_SHCreate a shared lock
LOCK_EXCreate an exclusive lock
LOCK_UNRelease our lock
LOCK_NBDon't block when setting the lock. Return an error if the action cannot be completed.

lockf(fd, operation, offset)
Locks or unlocks the portion of the file after offset. Allows you to lock just trailing portions of the file, if desired. lockf is just a front end for fcntl. Arguments:

F_LOCKCreate an exclusive lock
F_TLOCKCreate an exclusive lock or return an error immediately
F_ULOCKRelease our lock
F_TESTTest if the file is locked by another process.[3]

fcntl(fd, command, struct flock );
fcntl offers you the most locking control. The flock structure details the beginning and end of the segment to lock. It has arguments analogous to those for lockf and can differentiate between read and write locks. (fcntl can do other things too, such as setting the close on exec flag, duplicating a file descriptor, and more.)

Most languages have similar functions. For example Perl uses the flock function, which may use flock, lockf, or fcntl under the hood.

Now naturally, the most important thing about these locking mechanisms is that any application that could be accessing the files in question must also use the same locking mechanism.[4] And this is unfortunately a problem when you don't control all the software in question. Next week I'll cover mandatory locking, which can provide guarenteed locks even when not all processes cooperate.


[1] For example mail.local, procmail, etc

[2] The maildir mailbox format was created for just this reason. A maildir mailbox is simply a set of directories, with each email message stored in a separate file. This setup allows simultaneous access to the mailbox without requiring any locking functions whatsoever, functioning even on remotely mounted filesystems.

[3] Of course, this is a potential race condition, because between the test and any action you take, another process may lock the file.

[4] I.E. flock vs {lockf,fcntl}.

Bri Hatch is Chief Hacker at Onsight, Inc and author of Hacking Linux Exposed and Building Linux VPNs. He likes to periodically delete /etc/passwd and /etc/shadow and reboot to enforce the ultimate Linux locking system. Bri can be reached at bri@hackinglinuxexposed.com.

Copyright Bri Hatch, 2003

This is the June 16, 2003 issue of the Linux Security: Tips, Tricks, and Hackery newsletter. If you wish to subscribe, visit http://lists.onsight.com/ or send email to Linux_Security-request@lists.onsight.com.

previous article
next article