From a48226bb43e9672e8f4d5955b8c15cabdfbd1756 Mon Sep 17 00:00:00 2001 From: jilles Date: Fri, 7 Mar 2014 16:43:08 +0000 Subject: MFC r261859: 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. --- lib/libc/gen/fts.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index d15be06..d98a94b 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -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); 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_parent); /* 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_parent); SET(FTS_STOP); return (NULL); } + free(tmp); p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; return (sp->fts_cur = p); } -- cgit v1.1