diff options
author | Russell Bryant <russell@digium.com> | 2008-08-02 20:42:54 +0000 |
---|---|---|
committer | Russell Bryant <russell@digium.com> | 2008-08-02 20:42:54 +0000 |
commit | 62d3093fd2a1ce995f1123f5c1341262761f417d (patch) | |
tree | 7daeafbf6c24d3f450c2b76049f6362031969531 /drivers/dahdi/dahdi-base.c | |
parent | 0cd78215ef045fa2cfa87ef423526b53fe5b3fd2 (diff) |
Rework free_tone_zone a bit to avoid a potential memory leak in a weird scenario.
It was theoretically possible that a zone was registered after we removed a zone,
but before we tried to put it back after determining that it was busy. If this
occurred, then when putting the zone back, we would overwrite the reference to
the newly created zone, leaking the associated memory.
git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@4673 a0bf4364-ded3-4de4-8d8a-66a801d63aff
Diffstat (limited to 'drivers/dahdi/dahdi-base.c')
-rw-r--r-- | drivers/dahdi/dahdi-base.c | 27 |
1 files changed, 12 insertions, 15 deletions
diff --git a/drivers/dahdi/dahdi-base.c b/drivers/dahdi/dahdi-base.c index 2bb2f0b..695ce20 100644 --- a/drivers/dahdi/dahdi-base.c +++ b/drivers/dahdi/dahdi-base.c @@ -1183,30 +1183,27 @@ static void close_channel(struct dahdi_chan *chan) static int free_tone_zone(int num) { - struct dahdi_zone *z; + struct dahdi_zone *z = NULL; + int res = 0; if ((num >= DAHDI_TONE_ZONE_MAX) || (num < 0)) return -EINVAL; write_lock(&zone_lock); - z = tone_zones[num]; - tone_zones[num] = NULL; + if (tone_zones[num]) { + if (!atomic_read(&tone_zones[num]->refcount)) { + z = tone_zones[num]; + tone_zones[num] = NULL; + } else { + res = -EBUSY; + } + } write_unlock(&zone_lock); - if (!z) - return 0; - if (atomic_read(&z->refcount)) { - /* channels are still using this zone so put it back */ - write_lock(&zone_lock); - tone_zones[num] = z; - write_unlock(&zone_lock); - - return -EBUSY; - } else { + if (z) kfree(z); - return 0; - } + return res; } static int dahdi_register_tone_zone(int num, struct dahdi_zone *zone) |