From 10fa8fe8d0a1146323a9bc4b4c4feb3d6275c5d7 Mon Sep 17 00:00:00 2001
From: David Vossel <dvossel@digium.com>
Date: Fri, 6 Nov 2009 22:35:44 +0000
Subject: [PATCH] Merged revisions 228692 via svnmerge from
 https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r228692 | dvossel | 2009-11-06 16:33:27 -0600 (Fri, 06 Nov 2009) | 9 lines

  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: https://origsvn.digium.com/svn/asterisk/trunk@228693 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 main/channel.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/main/channel.c b/main/channel.c
index ce74b3f266..dd3d110961 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -4014,6 +4014,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
@@ -4024,13 +4029,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;
 					}
 				}
-- 
GitLab