mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 19:34:43 +01:00
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 git-svn-id: svn+ssh://svn.freebsd.org/base/head@261589 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f
This commit is contained in:
1 parent
d2e2d2ecbc
commit
c6d38f088e
1 file changed
+8
-4
+8
-4
@@ -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_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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user