[PATCH 1/4] vfs: plug a use-after-free of fd_rdir in namei
    Mateusz Guzik 
    mjguzik at gmail.com
       
    Wed Jul  8 22:07:19 UTC 2015
    
    
  
From: Mateusz Guzik <mjg at freebsd.org>
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.
MFC after:	1 week
---
 sys/kern/vfs_lookup.c | 6 ++++++
 1 file changed, 6 insertions(+)
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index 5dc07dc..20f8e96 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -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;
-- 
2.4.5
    
    
More information about the freebsd-fs
mailing list