Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Jul 2015 15:06:25 +0000 (UTC)
From:      Mateusz Guzik <mjg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r285319 - head/sys/kern
Message-ID:  <201507091506.t69F6Pli098043@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mjg
Date: Thu Jul  9 15:06:24 2015
New Revision: 285319
URL: https://svnweb.freebsd.org/changeset/base/285319

Log:
  vfs: plug a use-after-free of fd_rdir in namei
  
  fd_rdir vnode was stored in ni_rootdir without refing it in any way,
  after which the filedsc lock was being dropped.
  
  The vnode could have been freed by mountcheckdirs or another thread doing
  chroot.
  
  VREF the vnode while the lock is held.
  
  Reviewed by:	kib
  MFC after:	1 week

Modified:
  head/sys/kern/vfs_lookup.c

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c	Thu Jul  9 14:14:44 2015	(r285318)
+++ head/sys/kern/vfs_lookup.c	Thu Jul  9 15:06:24 2015	(r285319)
@@ -210,6 +210,7 @@ namei(struct nameidata *ndp)
 	 */
 	FILEDESC_SLOCK(fdp);
 	ndp->ni_rootdir = fdp->fd_rdir;
+	VREF(ndp->ni_rootdir);
 	ndp->ni_topdir = fdp->fd_jdir;
 
 	/*
@@ -260,6 +261,7 @@ namei(struct nameidata *ndp)
 			}
 		}
 		if (error) {
+			vrele(ndp->ni_rootdir);
 			namei_cleanup_cnp(cnp);
 			return (error);
 		}
@@ -286,6 +288,7 @@ namei(struct nameidata *ndp)
 				if (KTRPOINT(curthread, KTR_CAPFAIL))
 					ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
 #endif
+				vrele(ndp->ni_rootdir);
 				namei_cleanup_cnp(cnp);
 				return (ENOTCAPABLE);
 			}
@@ -299,6 +302,7 @@ namei(struct nameidata *ndp)
 		ndp->ni_startdir = dp;
 		error = lookup(ndp);
 		if (error) {
+			vrele(ndp->ni_rootdir);
 			namei_cleanup_cnp(cnp);
 			SDT_PROBE(vfs, namei, lookup, return, error, NULL, 0,
 			    0, 0);
@@ -308,6 +312,7 @@ namei(struct nameidata *ndp)
 		 * If not a symbolic link, we're done.
 		 */
 		if ((cnp->cn_flags & ISSYMLINK) == 0) {
+			vrele(ndp->ni_rootdir);
 			if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) {
 				namei_cleanup_cnp(cnp);
 			} else
@@ -371,6 +376,7 @@ namei(struct nameidata *ndp)
 		vput(ndp->ni_vp);
 		dp = ndp->ni_dvp;
 	}
+	vrele(ndp->ni_rootdir);
 	namei_cleanup_cnp(cnp);
 	vput(ndp->ni_vp);
 	ndp->ni_vp = NULL;



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