diff options
author | jilles <jilles@FreeBSD.org> | 2014-03-07 16:43:08 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2014-03-07 16:43:08 +0000 |
commit | a48226bb43e9672e8f4d5955b8c15cabdfbd1756 (patch) | |
tree | 1761dfaec8bbd031c4eb0abb25767b18947b3a40 /lib | |
parent | a887dd1976ef3a88756e362b7933a80b0dccc608 (diff) | |
download | FreeBSD-src-a48226bb43e9672e8f4d5955b8c15cabdfbd1756.zip FreeBSD-src-a48226bb43e9672e8f4d5955b8c15cabdfbd1756.tar.gz |
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.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/gen/fts.c | 12 |
1 files changed, 8 insertions, 4 deletions
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); } |