Skip to content

Commit

Permalink
tracer: fix possible double free during dialog tracing
Browse files Browse the repository at this point in the history
The initial transaction info free algorithm was to release the memory
when there is no other tracing instance running. However, when engaging
dialog tracing, a single dialog tracing instance is created, without a
transaction one. But, when the BYE is received, it is traced using the
transaction tracing, without an instance. Thus, the free function is
called twice, once for dialog and once for transaction:
 * first call will find the dialog instance and release it, and release
   the info (since there are no remaining instances)
 * the second call, for the transaction instances releases would
   basically access invalid memory, which could lead to either double
   free, or even memory corruptions (in case fragment would had been
   repurposed)

Credits for Vlad Paiu for troubleshooting, brainstorming and
providing useful logs

Fixes #2869
  • Loading branch information
razvancrainea committed Sep 2, 2022
1 parent c477e49 commit 184d1cd
Showing 1 changed file with 9 additions and 3 deletions.
12 changes: 9 additions & 3 deletions modules/tracer/tracer.c
Original file line number Diff line number Diff line change
Expand Up @@ -1364,22 +1364,25 @@ static void free_trace_info_shm(void *param, int type)
info->instances = it->next;
shm_free(it);
}
if (!prev)
if ((info->flags & ~TRACE_INFO_STAT) == 0)
shm_free(param);
}

static void free_trace_info_tm(void *param)
{
TRACE_FLAG_UNSET((trace_info_p)param, TRACE_INFO_TRAN);
free_trace_info_shm(param, TRACE_TRANSACTION);
}

static void free_trace_info_b2b(void *param)
{
TRACE_FLAG_UNSET((trace_info_p)param, TRACE_INFO_B2B);
free_trace_info_shm(param, TRACE_B2B);
}

static void free_trace_info_dlg(void *param)
{
TRACE_FLAG_UNSET((trace_info_p)param, TRACE_INFO_DIALOG);
free_trace_info_shm(param, TRACE_DIALOG);
}

Expand Down Expand Up @@ -1429,15 +1432,17 @@ static int trace_b2b_transaction(struct sip_msg* msg, void *trans, void* param)

static struct b2b_tracer* b2b_set_tracer_cb(void)
{
trace_info_p info = GET_TRACER_CONTEXT;
static struct b2b_tracer tracer;

/* as parameter, set the tracing info from the current contect */
tracer.param = (void*)GET_TRACER_CONTEXT;
tracer.param = (void*)info;

if (tracer.param==NULL) {
tracer.f = NULL;
tracer.f_freep = NULL;
} else {
TRACE_FLAG_SET(info, TRACE_INFO_B2B);
tracer.f = trace_b2b_transaction;
tracer.f_freep = free_trace_info_b2b;
}
Expand Down Expand Up @@ -1535,9 +1540,11 @@ static int trace_dialog(struct sip_msg *msg, trace_info_p info)
/* here also free trace info param because we are sure that
* this callback is ran only once - when dialog gets for
* the first time in DELETED state */
TRACE_FLAG_SET(info, TRACE_INFO_DIALOG);
if(dlgb.register_dlgcb(dlg,DLGCB_TERMINATED,
trace_transaction_dlgcb,info,free_trace_info_dlg)!=0) {
LM_ERR("failed to register dialog callback\n");
TRACE_FLAG_UNSET(info, TRACE_INFO_DIALOG);
return -1;
}

Expand All @@ -1553,7 +1560,6 @@ static int trace_dialog(struct sip_msg *msg, trace_info_p info)
return -1;
}

TRACE_FLAG_SET(info, TRACE_INFO_DIALOG);
return 0;
}

Expand Down

0 comments on commit 184d1cd

Please sign in to comment.