Fix tmpfs_lookup locking for ".." == ".". unveil_find_cover() calls
authorpatrick <patrick@openbsd.org>
Sat, 23 Oct 2021 17:38:00 +0000 (17:38 +0000)
committerpatrick <patrick@openbsd.org>
Sat, 23 Oct 2021 17:38:00 +0000 (17:38 +0000)
VFS_LOOKUP(dir, &parent) in a loop and looks up the parent directory
".." repeatedly. VFS_LOOKUP is expected to unlock 'dir' and return
'parent' locked.

So tmpfs_lookup() is called for ISDOTDOT and:
- runs with dvp = dir, vpp = &parent
- gets parent from tmpfs_vnode_get() and
- re-locks dir with vn_lock(dvp)
but skips the call to
VOP_UNLOCK(dvp);
on return because *vpp == dvp

The reason for doing so is the lookup for ".".  In this case
tmpfs_lookup() just increases the reference on dvp and copies the
pointer:
*vpp = dvp; vref(dvp);

However, in our case we also have *vpp == dvp, but for a different
lookup (ISDOTDOT), so we must do the unlock.

From markus@

sys/tmpfs/tmpfs_vnops.c

index daeb134..b1a4fe2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tmpfs_vnops.c,v 1.46 2021/03/11 13:31:35 jsg Exp $    */
+/*     $OpenBSD: tmpfs_vnops.c,v 1.47 2021/10/23 17:38:00 patrick Exp $        */
 /*     $NetBSD: tmpfs_vnops.c,v 1.100 2012/11/05 17:27:39 dholland Exp $       */
 
 /*
@@ -289,12 +289,12 @@ done:
        }
 out:
        /*
-        * If (1) we succeeded, (2) found a distinct vnode to return and (3)
+        * If (1) we succeeded, (2) found a distinct vnode != .. to return and (3)
         * were either explicitly told to keep the parent locked or are in the
         * middle of a lookup, unlock the parent vnode.
         */
        if ((error == 0 || error == EJUSTRETURN) && /* (1) */
-           *vpp != dvp &&                          /* (2) */
+           (*vpp != dvp || (cnp->cn_flags & ISDOTDOT))  && /* (2) */
            (!lockparent || !lastcn)) {             /* (3) */
                VOP_UNLOCK(dvp);
                cnp->cn_flags |= PDIRUNLOCK;