summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Coffman <kwc@citi.umich.edu>2007-02-08 17:27:19 -0500
committerNeil Brown <neilb@suse.de>2007-02-09 11:43:04 +1100
commit4a2e207f73f9ebe938e882f9419a2716fe751481 (patch)
tree83146c77aaa8a92bbc2eae2aa5924eb0e63bc8f7
parente54fb292fcd9253743fc17ba0af26dcbb0723a5d (diff)
downloadnfs-utils-4a2e207f73f9ebe938e882f9419a2716fe751481.tar.gz
nfs-utils-4a2e207f73f9ebe938e882f9419a2716fe751481.tar.xz
nfs-utils-4a2e207f73f9ebe938e882f9419a2716fe751481.zip
Stop using storage after free
Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Kevin Coffman <kwc@citi.umich.edu> The previous patch seems to expose a use after free bug in dirscancb. At least, I could reliably reproduce a segfault by doing a bunch of mounts and then unmounting them all. The code uses the following list macro: TAILQ_FOREACH(ic, icq, ic_next) { ...to iterate over all of the ic entries and clean up any that no longer have a corresponding directory in rpc_pipefs. This macro unrolls into: for(ic=icq->tqh_first; ic != NULL; ic=ic->ic_next.tqe_next) { ...but within this loop, we can free ic, and then the for loop can trip over that when it tries to do the iteration. The attached patch works around this by not using the TAILQ_FOREACH macro and saving off the tqe_next pointer prior to the free. Again, this was tested on a patched 1.0.6, but the 1.0.10 code is very similar, and I think the problem exists there as well. Signed-off-by: Neil Brown <neilb@suse.de>
-rw-r--r--utils/idmapd/idmapd.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
index cbb0b6a..b30b69e 100644
--- a/utils/idmapd/idmapd.c
+++ b/utils/idmapd/idmapd.c
@@ -444,7 +444,7 @@ dirscancb(int fd, short which, void *data)
{
int nent, i;
struct dirent **ents;
- struct idmap_client *ic;
+ struct idmap_client *ic, *nextic;
char path[PATH_MAX];
struct idmap_clientq *icq = data;
@@ -498,7 +498,9 @@ dirscancb(int fd, short which, void *data)
}
}
- TAILQ_FOREACH(ic, icq, ic_next) {
+ ic = TAILQ_FIRST(icq);
+ while(ic != NULL) {
+ nextic=TAILQ_NEXT(ic, ic_next);
if (!ic->ic_scanned) {
event_del(&ic->ic_event);
close(ic->ic_fd);
@@ -511,6 +513,7 @@ dirscancb(int fd, short which, void *data)
free(ic);
} else
ic->ic_scanned = 0;
+ ic = nextic;
}
out: