From 71b704ef788a5a974e962815239083af594bb51e Mon Sep 17 00:00:00 2001 From: Mark Michelson Date: Thu, 17 Apr 2008 16:28:03 +0000 Subject: [PATCH] It was possible for a reference to a frame which was part of a freed DSP to still be referenced, leading to memory corruption and eventual crashes. This code change ensures that the dsp is freed when we are finished with the frame. This change is very similar to a change Russell made with translators back a month or so ago. (closes issue #11999) Reported by: destiny6628 Patches: 11999.patch uploaded by putnopvut (license 60) Tested by: destiny6628, victoryure git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@114207 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- include/asterisk/frame.h | 4 ++++ main/dsp.c | 33 ++++++++++++++++++++++++++++++++- main/frame.c | 3 +++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 9165b34e8a..30686efdea 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -131,6 +131,10 @@ enum { * The translator can not be free'd if the frame inside of it still has * this flag set. */ AST_FRFLAG_FROM_TRANSLATOR = (1 << 1), + /*! This frame came from a dsp and is still the original frame. + * The dsp cannot be free'd if the frame inside of it still has + * this flag set. */ + AST_FRFLAG_FROM_DSP = (1 << 2), }; /*! \brief Data structure associated with a single frame of data diff --git a/main/dsp.c b/main/dsp.c index 4ec1a82656..3caf65027e 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -1486,6 +1486,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, memset(&dsp->f, 0, sizeof(dsp->f)); dsp->f.frametype = AST_FRAME_NULL; ast_frfree(af); + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } if ((dsp->features & DSP_FEATURE_BUSY_DETECT) && ast_dsp_busydetect(dsp)) { @@ -1494,7 +1495,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, dsp->f.frametype = AST_FRAME_CONTROL; dsp->f.subclass = AST_CONTROL_BUSY; ast_frfree(af); - ast_log(LOG_DEBUG, "Requesting Hangup because the busy tone was detected on channel %s\n", chan->name); + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } if ((dsp->features & DSP_FEATURE_DTMF_DETECT)) { @@ -1516,6 +1517,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, if (chan) ast_queue_frame(chan, af); ast_frfree(af); + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } } else { @@ -1542,6 +1544,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, ast_queue_frame(chan, af); ast_frfree(af); } + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } else { memset(&dsp->f, 0, sizeof(dsp->f)); @@ -1559,6 +1562,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, if (chan) ast_queue_frame(chan, af); ast_frfree(af); + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } } @@ -1575,6 +1579,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, if (chan) ast_queue_frame(chan, af); ast_frfree(af); + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } } else { @@ -1588,6 +1593,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, if (chan) ast_queue_frame(chan, af); ast_frfree(af); + ast_set_flag(&dsp->f, AST_FRFLAG_FROM_DSP); return &dsp->f; } } @@ -1658,6 +1664,17 @@ void ast_dsp_set_features(struct ast_dsp *dsp, int features) void ast_dsp_free(struct ast_dsp *dsp) { + if (ast_test_flag(&dsp->f, AST_FRFLAG_FROM_DSP)) { + /* If this flag is still set, that means that the dsp's destruction + * been torn down, while we still have a frame out there being used. + * When ast_frfree() gets called on that frame, this ast_trans_pvt + * will get destroyed, too. */ + + /* Set the magic hint that this has been requested to be destroyed. */ + dsp->freqcount = -1; + + return; + } free(dsp); } @@ -1786,3 +1803,17 @@ int ast_dsp_get_tcount(struct ast_dsp *dsp) { return dsp->tcount; } + +void ast_dsp_frame_freed(struct ast_frame *fr) +{ + struct ast_dsp *dsp; + + ast_clear_flag(fr, AST_FRFLAG_FROM_DSP); + + dsp = (struct ast_dsp *) (((char *) fr) - offsetof(struct ast_dsp, f)); + + if (dsp->freqcount != -1) + return; + + ast_dsp_free(dsp); +} diff --git a/main/frame.c b/main/frame.c index 5c4613f4d2..d2240efb01 100644 --- a/main/frame.c +++ b/main/frame.c @@ -321,6 +321,8 @@ void ast_frame_free(struct ast_frame *fr, int cache) { if (ast_test_flag(fr, AST_FRFLAG_FROM_TRANSLATOR)) ast_translate_frame_freed(fr); + else if (ast_test_flag(fr, AST_FRFLAG_FROM_DSP)) + ast_dsp_frame_freed(fr); if (!fr->mallocd) return; @@ -370,6 +372,7 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) void *newdata; ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR); + ast_clear_flag(fr, AST_FRFLAG_FROM_DSP); if (!(fr->mallocd & AST_MALLOCD_HDR)) { /* Allocate a new header if needed */