Author: mjg
Date: Mon Oct  5 19:38:51 2020
New Revision: 366462
URL: https://svnweb.freebsd.org/changeset/base/366462

Log:
  cache: fix pwd use-after-free in setting up fallback
  
  Since the code exits smr section prior to calling pwd_hold, the used
  pwd can be freed and a new one allocated with the same address, making
  the comparison erroneously true.
  
  Note it is very unlikely anyone ran into it.

Modified:
  head/sys/kern/kern_descrip.c
  head/sys/kern/vfs_cache.c
  head/sys/sys/filedesc.h

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c        Mon Oct  5 19:26:54 2020        
(r366461)
+++ head/sys/kern/kern_descrip.c        Mon Oct  5 19:38:51 2020        
(r366462)
@@ -3344,6 +3344,17 @@ pwd_hold_filedesc(struct filedesc *fdp)
        return (pwd);
 }
 
+bool
+pwd_hold_smr(struct pwd *pwd)
+{
+
+       MPASS(pwd != NULL);
+       if (__predict_true(refcount_acquire_if_not_zero(&pwd->pwd_refcount))) {
+               return (true);
+       }
+       return (false);
+}
+
 struct pwd *
 pwd_hold(struct thread *td)
 {
@@ -3354,8 +3365,7 @@ pwd_hold(struct thread *td)
 
        vfs_smr_enter();
        pwd = vfs_smr_entered_load(&fdp->fd_pwd);
-       MPASS(pwd != NULL);
-       if (__predict_true(refcount_acquire_if_not_zero(&pwd->pwd_refcount))) {
+       if (pwd_hold_smr(pwd)) {
                vfs_smr_exit();
                return (pwd);
        }

Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c   Mon Oct  5 19:26:54 2020        (r366461)
+++ head/sys/kern/vfs_cache.c   Mon Oct  5 19:38:51 2020        (r366462)
@@ -3484,25 +3484,24 @@ cache_fplookup_partial_setup(struct cache_fpl *fpl)
 
        ndp = fpl->ndp;
        cnp = fpl->cnp;
+       pwd = fpl->pwd;
        dvp = fpl->dvp;
        dvp_seqc = fpl->dvp_seqc;
 
-       dvs = vget_prep_smr(dvp);
-       if (__predict_false(dvs == VGET_NONE)) {
+       if (!pwd_hold_smr(pwd)) {
                cache_fpl_smr_exit(fpl);
                return (cache_fpl_aborted(fpl));
        }
 
+       dvs = vget_prep_smr(dvp);
        cache_fpl_smr_exit(fpl);
-
-       vget_finish_ref(dvp, dvs);
-       if (!vn_seqc_consistent(dvp, dvp_seqc)) {
-               vrele(dvp);
+       if (__predict_false(dvs == VGET_NONE)) {
+               pwd_drop(pwd);
                return (cache_fpl_aborted(fpl));
        }
 
-       pwd = pwd_hold(curthread);
-       if (fpl->pwd != pwd) {
+       vget_finish_ref(dvp, dvs);
+       if (!vn_seqc_consistent(dvp, dvp_seqc)) {
                vrele(dvp);
                pwd_drop(pwd);
                return (cache_fpl_aborted(fpl));

Modified: head/sys/sys/filedesc.h
==============================================================================
--- head/sys/sys/filedesc.h     Mon Oct  5 19:26:54 2020        (r366461)
+++ head/sys/sys/filedesc.h     Mon Oct  5 19:38:51 2020        (r366462)
@@ -302,6 +302,7 @@ void        pwd_ensure_dirs(void);
 void   pwd_set_rootvnode(void);
 
 struct pwd *pwd_hold_filedesc(struct filedesc *fdp);
+bool   pwd_hold_smr(struct pwd *pwd);
 struct pwd *pwd_hold(struct thread *td);
 void   pwd_drop(struct pwd *pwd);
 static inline void
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to