Fix crash in chan_sip when a core initiated op occurs at the same time as a BYE
When a BYE request is processed in chan_sip, the current SIP dialog is detached from its associated Asterisk channel structure. The tech_pvt pointer in the channel object is set to NULL, and the dialog persists for an RFC mandated period of time to handle re-transmits. While this process occurs, the channel is locked (which is good). Unfortunately, operations that are initiated externally have no way of knowing that the channel they've just obtained (which is still valid) and that they are attempting to lock is about to have its tech_pvt pointer removed. By the time they obtain the channel lock and call the channel technology callback, the tech_pvt is NULL. This patch adds a few checks to some channel callbacks that make sure the tech_pvt isn't NULL before using it. Prime offenders were the DTMF digit callbacks, which would crash if AMI initiated a DTMF on the channel at the same time as a BYE was received from the UA. This patch also adds checks on sip_transfer (as AMI can also cause a callback into this function), as well as sip_indicate (as lots of things can queue an indication onto a channel). Review: https://reviewboard.asterisk.org/r/2434/ (closes issue ASTERISK-20225) Reported by: Jeff Hoppe ........ Merged revisions 385170 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 385173 from http://svn.asterisk.org/svn/asterisk/branches/11 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@385174 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
d09eeaa8eb
commit
caf4a5f605
|
@ -7352,6 +7352,11 @@ static int sip_answer(struct ast_channel *ast)
|
||||||
int res = 0;
|
int res = 0;
|
||||||
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
ast_debug(1, "Asked to answer channel %s without tech pvt; ignoring\n",
|
||||||
|
ast_channel_name(ast));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
sip_pvt_lock(p);
|
sip_pvt_lock(p);
|
||||||
if (ast_channel_state(ast) != AST_STATE_UP) {
|
if (ast_channel_state(ast) != AST_STATE_UP) {
|
||||||
try_suggested_sip_codec(p);
|
try_suggested_sip_codec(p);
|
||||||
|
@ -7521,6 +7526,12 @@ static int sip_senddigit_begin(struct ast_channel *ast, char digit)
|
||||||
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
ast_debug(1, "Asked to begin DTMF digit on channel %s with no pvt; ignoring\n",
|
||||||
|
ast_channel_name(ast));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
sip_pvt_lock(p);
|
sip_pvt_lock(p);
|
||||||
switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
|
switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
|
||||||
case SIP_DTMF_INBAND:
|
case SIP_DTMF_INBAND:
|
||||||
|
@ -7545,6 +7556,12 @@ static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int d
|
||||||
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
ast_debug(1, "Asked to end DTMF digit on channel %s with no pvt; ignoring\n",
|
||||||
|
ast_channel_name(ast));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
sip_pvt_lock(p);
|
sip_pvt_lock(p);
|
||||||
switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
|
switch (ast_test_flag(&p->flags[0], SIP_DTMF)) {
|
||||||
case SIP_DTMF_INFO:
|
case SIP_DTMF_INFO:
|
||||||
|
@ -7570,6 +7587,12 @@ static int sip_transfer(struct ast_channel *ast, const char *dest)
|
||||||
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
ast_debug(1, "Asked to transfer channel %s with no pvt; ignoring\n",
|
||||||
|
ast_channel_name(ast));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (dest == NULL) /* functions below do not take a NULL */
|
if (dest == NULL) /* functions below do not take a NULL */
|
||||||
dest = "";
|
dest = "";
|
||||||
sip_pvt_lock(p);
|
sip_pvt_lock(p);
|
||||||
|
@ -7765,6 +7788,12 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
|
||||||
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
struct sip_pvt *p = ast_channel_tech_pvt(ast);
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
|
if (!p) {
|
||||||
|
ast_debug(1, "Asked to indicate condition on channel %s with no pvt; ignoring\n",
|
||||||
|
ast_channel_name(ast));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
sip_pvt_lock(p);
|
sip_pvt_lock(p);
|
||||||
switch(condition) {
|
switch(condition) {
|
||||||
case AST_CONTROL_RINGING:
|
case AST_CONTROL_RINGING:
|
||||||
|
|
Loading…
Reference in New Issue