summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authortruckman <truckman@FreeBSD.org>2005-10-14 22:13:33 +0000
committertruckman <truckman@FreeBSD.org>2005-10-14 22:13:33 +0000
commit10f007ca7dcc58198c5b122a663950ba305936d2 (patch)
tree00da476e762ac31f09c1022ab0c2231c130d0392 /sys/ufs
parent0d876e6b170adb77c59c0190df7d0eabace9a269 (diff)
downloadFreeBSD-src-10f007ca7dcc58198c5b122a663950ba305936d2.zip
FreeBSD-src-10f007ca7dcc58198c5b122a663950ba305936d2.tar.gz
Close a race in the ufs_lookup() code that handles the ISDOTDOT
case by saving the value of dp->i_ino before unlocking the vnode for the current directory and passing the saved value to VFS_VGET(). Without this change, another thread can overwrite dp->i_ino after the current directory is unlocked, causing ufs_lookup() to lock and return the wrong vnode in place of the vnode for its parent directory. A deadlock can occur if dp->i_ino was changed to a subdirectory of the current directory because the root to leaf vnode lock ordering will be violated. A vnode lock can be leaked if dp->i_ino was changed to point to the current directory, which causes the current vnode lock for the current directory to be recursed, which confuses lookup() into calling vrele() when it should be calling vput(). The probability of this bug being triggered seems to be quite low unless the sysctl variable debug.vfscache is set to 0. Reviewed by: jhb MFC after: 2 weeks
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ufs/ufs_lookup.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c
index e4332c1..b46237e 100644
--- a/sys/ufs/ufs/ufs_lookup.c
+++ b/sys/ufs/ufs/ufs_lookup.c
@@ -153,6 +153,7 @@ ufs_lookup(ap)
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
struct thread *td = cnp->cn_thread;
+ u_int32_t saved_ino;
bp = NULL;
slotoffset = -1;
@@ -557,8 +558,9 @@ found:
*/
pdp = vdp;
if (flags & ISDOTDOT) {
+ saved_ino = dp->i_ino;
VOP_UNLOCK(pdp, 0, td); /* race to get the inode */
- error = VFS_VGET(pdp->v_mount, dp->i_ino,
+ error = VFS_VGET(pdp->v_mount, saved_ino,
cnp->cn_lkflags, &tdp);
vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, td);
if (error)
OpenPOWER on IntegriCloud