svn commit: r261589 - head/lib/libc/gen

Jilles Tjoelker jilles at FreeBSD.org
Fri Feb 7 13:40:22 UTC 2014


Author: jilles
Date: Fri Feb  7 13:40:22 2014
New Revision: 261589
URL: http://svnweb.freebsd.org/changeset/base/261589

Log:
  fts: Fix double-free with conflicting concurrent modifications.
  
  If rare conditions such as concurrent conflicting manipulation of the
  filesystem occur, fts_read() frees the current FTSENT without adjusting
  the pointers in the FTS accordingly. A later fts_close() then frees the
  same FTSENT again.
  
  Reported by:	pho
  Tested by:	pho
  MFC after:	1 week

Modified:
  head/lib/libc/gen/fts.c

Modified: head/lib/libc/gen/fts.c
==============================================================================
--- head/lib/libc/gen/fts.c	Fri Feb  7 13:17:27 2014	(r261588)
+++ head/lib/libc/gen/fts.c	Fri Feb  7 13:40:22 2014	(r261589)
@@ -406,8 +406,6 @@ fts_read(FTS *sp)
 	/* Move to the next node on this level. */
 next:	tmp = p;
 	if ((p = p->fts_link) != NULL) {
-		free(tmp);
-
 		/*
 		 * If reached the top, return to the original directory (or
 		 * the root of the tree), and load the paths for the next root.
@@ -417,6 +415,7 @@ next:	tmp = p;
 				SET(FTS_STOP);
 				return (NULL);
 			}
+			free(tmp);
 			fts_load(sp, p);
 			return (sp->fts_cur = p);
 		}
@@ -426,8 +425,10 @@ next:	tmp = p;
 		 * ignore.  If followed, get a file descriptor so we can
 		 * get back if necessary.
 		 */
-		if (p->fts_instr == FTS_SKIP)
+		if (p->fts_instr == FTS_SKIP) {
+			free(tmp);
 			goto next;
+		}
 		if (p->fts_instr == FTS_FOLLOW) {
 			p->fts_info = fts_stat(sp, p, 1, -1);
 			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
@@ -441,6 +442,8 @@ next:	tmp = p;
 			p->fts_instr = FTS_NOINSTR;
 		}
 
+		free(tmp);
+
 name:		t = sp->fts_path + NAPPEND(p->fts_parent);
 		*t++ = '/';
 		memmove(t, p->fts_name, p->fts_namelen + 1);
@@ -449,13 +452,13 @@ name:		t = sp->fts_path + NAPPEND(p->fts
 
 	/* Move up to the parent node. */
 	p = tmp->fts_parent;
-	free(tmp);
 
 	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
 		/*
 		 * Done; free everything up and set errno to 0 so the user
 		 * can distinguish between error and EOF.
 		 */
+		free(tmp);
 		free(p);
 		errno = 0;
 		return (sp->fts_cur = NULL);
@@ -488,6 +491,7 @@ name:		t = sp->fts_path + NAPPEND(p->fts
 		SET(FTS_STOP);
 		return (NULL);
 	}
+	free(tmp);
 	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
 	return (sp->fts_cur = p);
 }


More information about the svn-src-head mailing list