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;
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to