svn commit: r366462 - in head/sys: kern sys

Mateusz Guzik mjg at FreeBSD.org
Mon Oct 5 19:38:52 UTC 2020


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


More information about the svn-src-all mailing list