diff options
author | kib <kib@FreeBSD.org> | 2009-04-16 09:57:08 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-04-16 09:57:08 +0000 |
commit | 915dee68f2d5bf06d202e877f12f1821e2ba4105 (patch) | |
tree | 279a95ca30b06a16f535ba760e5527905aad05f7 | |
parent | c6f719496778f47fc7163a1679ec2c4c5a5329f4 (diff) | |
download | FreeBSD-src-915dee68f2d5bf06d202e877f12f1821e2ba4105.zip FreeBSD-src-915dee68f2d5bf06d202e877f12f1821e2ba4105.tar.gz |
Verify that '..' still exists with the same inode number after
VFS_VGET() has returned in ufs_lookup(). If the '..' lookup started
immediately before the parent directory was removed, we might return
either cleared or unrelated inode otherwise.
Ufs_lookup() is split into new function ufs_lookup_() that either does
lookup, or verifies that directory entry exists and references supplied
inode number.
Reviewed by: tegge
Tested by: pho,
Andreas Tobler <andreast-list fgznet ch> (previous version)
MFC after: 1 month
-rw-r--r-- | sys/ufs/ufs/ufs_lookup.c | 44 |
1 files changed, 35 insertions, 9 deletions
diff --git a/sys/ufs/ufs/ufs_lookup.c b/sys/ufs/ufs/ufs_lookup.c index bc11a6a..da752a7 100644 --- a/sys/ufs/ufs/ufs_lookup.c +++ b/sys/ufs/ufs/ufs_lookup.c @@ -77,6 +77,9 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0, ""); /* true if old FS format...*/ #define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) +static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *, + ino_t); + /* * Convert a component of a pathname into a pointer to a locked inode. * This is a very central and rather complicated routine. @@ -130,7 +133,14 @@ ufs_lookup(ap) struct componentname *a_cnp; } */ *ap; { - struct vnode *vdp; /* vnode for directory being searched */ + + return (ufs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, 0)); +} + +static int +ufs_lookup_(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp, + ino_t dd_ino) +{ struct inode *dp; /* inode for directory being searched */ struct buf *bp; /* a buffer of directory entries */ struct direct *ep; /* the current directory entry */ @@ -150,8 +160,6 @@ ufs_lookup(ap) doff_t enduseful; /* pointer past last used dir slot */ u_long bmask; /* block offset mask */ int namlen, error; - struct vnode **vpp = ap->a_vpp; - struct componentname *cnp = ap->a_cnp; struct ucred *cred = cnp->cn_cred; int flags = cnp->cn_flags; int nameiop = cnp->cn_nameiop; @@ -164,9 +172,9 @@ ufs_lookup(ap) * XXX there was a soft-update diff about this I couldn't merge. * I think this was the equiv. */ - *vpp = NULL; + if (vpp != NULL) + *vpp = NULL; - vdp = ap->a_dvp; dp = VTOI(vdp); /* @@ -363,7 +371,7 @@ foundentry: slotoffset = i_offset; slotsize = ep->d_reclen; enduseful = dp->i_size; - ap->a_cnp->cn_flags |= ISWHITEOUT; + cnp->cn_flags |= ISWHITEOUT; numdirpasses--; goto notfound; } @@ -397,8 +405,8 @@ notfound: */ if ((nameiop == CREATE || nameiop == RENAME || (nameiop == DELETE && - (ap->a_cnp->cn_flags & DOWHITEOUT) && - (ap->a_cnp->cn_flags & ISWHITEOUT))) && + (cnp->cn_flags & DOWHITEOUT) && + (cnp->cn_flags & ISWHITEOUT))) && (flags & ISLASTCN) && dp->i_effnlink != 0) { /* * Access for write is interpreted as allowing @@ -453,7 +461,7 @@ notfound: * Insert name into cache (as non-existent) if appropriate. */ if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) - cache_enter(vdp, *vpp, cnp); + cache_enter(vdp, NULL, cnp); return (ENOENT); found: @@ -479,6 +487,12 @@ found: if ((flags & ISLASTCN) && nameiop == LOOKUP) dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1); + if (dd_ino != 0) { + if (ino != dd_ino) + return (ENOENT); + return (0); + } + /* * If deleting, and at end of pathname, return * parameters which can be used to remove file. @@ -580,6 +594,18 @@ found: error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp); if (error) return (error); + + /* + * Recheck that ".." entry in the vdp directory points + * to the inode we looked up before vdp lock was + * dropped. + */ + error = ufs_lookup_(pdp, NULL, cnp, ino); + if (error) { + vput(tdp); + return (error); + } + *vpp = tdp; } else if (dp->i_number == ino) { VREF(vdp); /* we want ourself, ie "." */ |