Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Aug 2017 16:23:44 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r322757 - head/sys/ufs/ffs
Message-ID:  <201708211623.v7LGNiuc094838@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Aug 21 16:23:44 2017
New Revision: 322757
URL: https://svnweb.freebsd.org/changeset/base/322757

Log:
  Avoid dereferencing potentially freed workitem in
  softdep_count_dependencies().
  
  Buffer's b_dep list is protected by the SU mount lock.  Owning the
  buffer lock is not enough to guarantee the stability of the list.
  
  Calculation of the UFS mount owning the workitems from the buffer must
  be much more careful to not dereference the work item which might be
  freed meantime.  To get to ump, use the pointers chain which does not
  involve workitems at all.
  
  Reported and tested by:	pho
  Reviewed by:	mckusick
  Sponsored by:	The FreeBSD Foundation
  MFC after:	2 weeks

Modified:
  head/sys/ufs/ffs/ffs_softdep.c

Modified: head/sys/ufs/ffs/ffs_softdep.c
==============================================================================
--- head/sys/ufs/ffs/ffs_softdep.c	Mon Aug 21 16:16:02 2017	(r322756)
+++ head/sys/ufs/ffs/ffs_softdep.c	Mon Aug 21 16:23:44 2017	(r322757)
@@ -13919,12 +13919,36 @@ softdep_count_dependencies(bp, wantcount)
 	struct newblk *newblk;
 	struct mkdir *mkdir;
 	struct diradd *dap;
+	struct vnode *vp;
+	struct mount *mp;
 	int i, retval;
 
 	retval = 0;
-	if ((wk = LIST_FIRST(&bp->b_dep)) == NULL)
+	if (LIST_EMPTY(&bp->b_dep))
 		return (0);
-	ump = VFSTOUFS(wk->wk_mp);
+	vp = bp->b_vp;
+
+	/*
+	 * The ump mount point is stable after we get a correct
+	 * pointer, since bp is locked and this prevents unmount from
+	 * proceed.  But to get to it, we cannot dereference bp->b_dep
+	 * head wk_mp, because we do not yet own SU ump lock and
+	 * workitem might be freed while dereferenced.
+	 */
+retry:
+	if (vp->v_type == VCHR) {
+		VOP_LOCK(vp, LK_RETRY | LK_EXCLUSIVE);
+		mp = vp->v_type == VCHR ? vp->v_rdev->si_mountpt : NULL;
+		VOP_UNLOCK(vp, 0);
+		if (mp == NULL)
+			goto retry;
+	} else if (vp->v_type == VREG) {
+		mp = vp->v_mount;
+	} else {
+		return (0);
+	}
+	ump = VFSTOUFS(mp);
+
 	ACQUIRE_LOCK(ump);
 	LIST_FOREACH(wk, &bp->b_dep, wk_list) {
 		switch (wk->wk_type) {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201708211623.v7LGNiuc094838>