chan_sip: Fix theoretical leak of p->refer.

If transmit_refer is called when p->refer is already allocated,
it leaks the previous allocation.  Updated code to always free
previous allocation during a new allocation.  Also instead of
checking if we have a previous allocation, always create a
clean record.

ASTERISK-15242 #close
Reported by: David Woolley
Review: https://reviewboard.asterisk.org/r/4160/


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@428117 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Corey Farrell
2014-11-17 15:56:11 +00:00
parent f20ddb1285
commit b3e0d05aad

View File

@@ -1431,6 +1431,7 @@ static int dialog_find_multiple(void *obj, void *arg, int flags);
static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt);
/* static int sip_addrcmp(char *name, struct sockaddr_in *sin); Support for peer matching */
static int sip_refer_alloc(struct sip_pvt *p);
static void sip_refer_destroy(struct sip_pvt *p);
static int sip_notify_alloc(struct sip_pvt *p);
static void ast_quiet_chan(struct ast_channel *chan);
static int attempt_transfer(struct sip_dual *transferer, struct sip_dual *target);
@@ -6405,14 +6406,7 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
ast_udptl_destroy(p->udptl);
p->udptl = NULL;
}
if (p->refer) {
if (p->refer->refer_call) {
p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
}
ast_string_field_free_memory(p->refer);
ast_free(p->refer);
p->refer = NULL;
}
sip_refer_destroy(p);
if (p->route) {
free_old_route(p->route);
p->route = NULL;
@@ -15374,10 +15368,24 @@ static int transmit_message(struct sip_pvt *p, int init, int auth)
/*! \brief Allocate SIP refer structure */
static int sip_refer_alloc(struct sip_pvt *p)
{
sip_refer_destroy(p);
p->refer = ast_calloc_with_stringfields(1, struct sip_refer, 512);
return p->refer ? 1 : 0;
}
/*! \brief Destroy SIP refer structure */
static void sip_refer_destroy(struct sip_pvt *p)
{
if (p->refer) {
if (p->refer->refer_call) {
p->refer->refer_call = dialog_unref(p->refer->refer_call, "unref dialog p->refer->refer_call");
}
ast_string_field_free_memory(p->refer);
ast_free(p->refer);
p->refer = NULL;
}
}
/*! \brief Allocate SIP refer structure */
static int sip_notify_alloc(struct sip_pvt *p)
{
@@ -17862,8 +17870,9 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq)
struct sip_refer *refer = NULL;
const char *transfer_context = NULL;
if (!p->refer && !sip_refer_alloc(p))
if (!sip_refer_alloc(p)) {
return -1;
}
refer = p->refer;
@@ -25342,7 +25351,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
replace_id = ast_strdupa(p_replaces);
ast_uri_decode(replace_id, ast_uri_sip_user);
if (!p->refer && !sip_refer_alloc(p)) {
if (!sip_refer_alloc(p)) {
transmit_response_reliable(p, "500 Server Internal Error", req);
append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -26302,7 +26311,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
}
/* Allocate memory for call transfer data */
if (!p->refer && !sip_refer_alloc(p)) {
if (!sip_refer_alloc(p)) {
transmit_response(p, "500 Internal Server Error", req);
append_history(p, "Xfer", "Refer failed. Memory allocation error.");
res = -3;