diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-11-06 22:33:27 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-11-06 22:33:27 +0000 |
commit | d3f14c2da612683a4f0b0f6e208390c602596f87 (patch) | |
tree | 34159a0fe8c67acc09dc00373691084a3f64c15c /main/channel.c | |
parent | e93ac767d88ff4e2bae84eaa60d37b779fc049d3 (diff) |
fixes audiohook write crash occuring in chan_spy whisper mode.
After writing to the audiohook list in ast_write(), frames
were being freed incorrectly. Under certain conditions this
resulted in a double free crash.
(closes issue #16133)
Reported by: wetwired
(closes issue #16045)
Reported by: bluecrow76
Patches:
issue16045.diff uploaded by dvossel (license 671)
Tested by: bluecrow76, dvossel, habile
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@228692 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main/channel.c')
-rw-r--r-- | main/channel.c | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/main/channel.c b/main/channel.c index 17f99ed38..3c772cf5b 100644 --- a/main/channel.c +++ b/main/channel.c @@ -2949,6 +2949,11 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) if (chan->audiohooks) { struct ast_frame *prev = NULL, *new_frame, *cur, *dup; + int freeoldlist = 0; + + if (f != fr) { + freeoldlist = 1; + } /* Since ast_audiohook_write may return a new frame, and the cur frame is * an item in a list of frames, create a new list adding each cur frame back to it @@ -2959,13 +2964,16 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr) /* if this frame is different than cur, preserve the end of the list, * free the old frames, and set cur to be the new frame */ if (new_frame != cur) { + /* doing an ast_frisolate here seems silly, but we are not guaranteed the new_frame * isn't part of local storage, meaning if ast_audiohook_write is called multiple * times it may override the previous frame we got from it unless we dup it */ if ((dup = ast_frisolate(new_frame))) { AST_LIST_NEXT(dup, frame_list) = AST_LIST_NEXT(cur, frame_list); - ast_frfree(new_frame); - ast_frfree(cur); + if (freeoldlist) { + AST_LIST_NEXT(cur, frame_list) = NULL; + ast_frfree(cur); + } cur = dup; } } |