summaryrefslogtreecommitdiff
path: root/drivers/dahdi/dahdi-base.c
diff options
context:
space:
mode:
authorRussell Bryant <russell@digium.com>2008-08-02 20:42:54 +0000
committerRussell Bryant <russell@digium.com>2008-08-02 20:42:54 +0000
commit62d3093fd2a1ce995f1123f5c1341262761f417d (patch)
tree7daeafbf6c24d3f450c2b76049f6362031969531 /drivers/dahdi/dahdi-base.c
parent0cd78215ef045fa2cfa87ef423526b53fe5b3fd2 (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.c27
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)