kern/94256: nfs locking/rpc.lockd doesn't understand file descriptor sharing

Kris Kennaway kris at FreeBSD.org
Wed Mar 8 18:20:09 PST 2006


>Number:         94256
>Category:       kern
>Synopsis:       nfs locking/rpc.lockd doesn't understand file descriptor sharing
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Mar 09 02:20:06 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Kris Kennaway
>Release:        FreeBSD 6.0-STABLE i386
>Organization:
FreeBSD
>Environment:
System: FreeBSD xor.obsecurity.org 6.0-STABLE FreeBSD 6.0-STABLE #13: Sun Nov 6 12:45:25 EST 2005 kkenn at xor.obsecurity.org:/mnt/src/sys/i386/compile/XOR i386
>Description:

NFS locking uses an 'svid' field for indicating ownership of lock
requests.  In the FreeBSD implementation this is the pid of the
process performing the lock request on the NFS client.

The rpc.lockd server uses this field to decide whether a process
requesting an unlock operation is holding a lock.  i.e. it assumes
that the pid that locks a file is the only process that can
legitimately perform the corresponding unlock operation.

This is false in a UNIX world, because file descriptors may be passed
between processes.  For example, a process may lock a file, fork, and
the child process inherits the file descriptor table and may
legitimately unlock the file.

When rpc.lockd receives an unlock request with svid that does not
match the recorded svid of the corresponding lock, it returns an
"unlock granted" to the client but does not actually pass the unlock
operation to the kernel.  Presumably this is for purposes of crash
recovery, in which the lock state may have been lost by the rpc.lockd
server and the client process really did own the lock.

The result of this is that locks may be "leaked" by the server, e.g.:

>How-To-Repeat:

On the NFS client:

haessal# daemon -p pid sleep 100000    <-- the daemon process creates and locks pid
haessal# kill -KILL `cat pid`          <-- the unlock request is generated by the child pid
haessal# lockf -t 0 -k pid echo Yay    <-- the server ignored it since it doesn't know the child inherited the lock
lockf: pid: already locked

On the NFS server:

dosirak# lockf -t 0 -k pid echo Yay
lockf: pid: already locked

>Fix:

Probably difficult.

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list