Skip to content

[CRASH] RTP_RELAY module crash for SIPREC BYE message #3893

@sahmed-bw

Description

@sahmed-bw

OpenSIPS version you are running

version: opensips 3.6.5 (x86_64/linux)
flags: STATS: On, DISABLE_NAGLE, USE_MCAST, SHM_MMAP, PKG_MALLOC, Q_MALLOC, F_MALLOC, HP_MALLOC, F_PARALLEL_MALLOC, DBG_MALLOC, FAST_LOCK-ADAPTIVE_WAIT
ADAPTIVE_WAIT_LOOPS=1024, MAX_RECV_BUFFER_SIZE 262144, MAX_LISTEN 16, MAX_URI_SIZE 1024, BUF_SIZE 65535
poll method support: poll, epoll, sigio_rt, select.
git revision: 42f57f043
main.c compiled on 05:28:42 May 16 2026 with cc 14

Crash Core Dump

Program terminated with signal SIGSEGV, Segmentation fault.
#0  parse_from_header (msg=msg@entry=0x0) at parser/parse_from.c:50
50		if ( !msg->from && ( parse_headers(msg,HDR_FROM_F,0)==-1 || !msg->from)) {
(gdb) bt full
#0  parse_from_header (msg=msg@entry=0x0) at parser/parse_from.c:50
        from_b = <optimized out>
        __FUNCTION__ = "parse_from_header"
        error = <optimized out>
#1  0x00007f7bd9ddee68 in get_from_tag (_m=0x0, _tag=_tag@entry=0x7ffd7ef01638) at nhelpr_funcs.c:229
        __FUNCTION__ = "get_from_tag"
#2  0x00007f7bd9dece29 in rtpproxy_fill_call_args (sess=0x7ffd7ef017d0, args=args@entry=0x7ffd7ef01600, ip=ip@entry=0x0, type=type@entry=0x0, 
    in_iface=in_iface@entry=0x0, out_iface=out_iface@entry=0x0, global_flags=global_flags@entry=0x0, flags=0x0, extra_flags=0x0) at rtpproxy.c:5079
        p = <optimized out>
        b = <optimized out>
        __FUNCTION__ = "rtpproxy_fill_call_args"
#3  0x00007f7bd9e0be28 in rtpproxy_api_delete (sess=<optimized out>, server=0x7f7bda453660, flags=<optimized out>, extra=<optimized out>) at rtpproxy.c:5300
        ret = -1
        rset = 0x0
        args = {arg1 = 0x0, arg2 = 0x0, offer = 0, body = {s = 0x0, len = 0}, callid = {s = 0x0, len = 0}, from_tag = {s = 0x0, len = 0}, to_tag = {s = 0x0, len = 0}, 
          set = 0x0, node = 0x0, raddr = {s = 0x0, len = 0}}
        __FUNCTION__ = "rtpproxy_api_delete"
#4  0x00007f7bd9da81b9 in rtp_relay_delete (info=0x7ffd7ef017d0, ctx=<optimized out>, sess=0x7f7bda453650, leg=<optimized out>) at rtp_relay_ctx.c:1326
        ret = <optimized out>
        __FUNCTION__ = "rtp_relay_delete"
#5  0x00007f7bd9db58df in rtp_relay_delete_ctx (ctx=0x7f7bda4531d0, sess=0x7f7bda453650, leg=0) at rtp_relay_ctx.c:1475
        info = {msg = 0x0, branch = -1, callid = 0x7f7bda4531f8, from_tag = 0x0, to_tag = 0x7f7bda453218, body = 0x0}
#6  rtp_relay_dlg_end (dlg=<optimized out>, type=<optimized out>, params=<optimized out>) at rtp_relay_ctx.c:1515
        ltype = 0
        ctx = 0x7f7bda4531d0
#7  0x00007f7bd9e7e63f in run_dlg_callbacks (type=type@entry=32, dlg=dlg@entry=0x7f7bda4510b0, msg=msg@entry=0x7f7bdc0a0a60, dir=<optimized out>, 
    dst_leg=<optimized out>, dlg_data=dlg_data@entry=0x0, locked=locked@entry=0, is_active=is_active@entry=1) at dlg_cb.c:256
        cb = 0x7f7bda457f60
        __FUNCTION__ = "run_dlg_callbacks"
#8  0x00007f7bd9eb256f in dlg_onroute (req=<optimized out>, route_params=<optimized out>, param=<optimized out>) at dlg_handlers.c:2158
        dlg = <optimized out>
        val = {
          s = 0x55ebe8597fa5 <buf+261> "57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: Performance Test\r\nContent-Length: 0\r\n\r\n", len = 11}
        callid = {
          s = 0x55ebe8597f6e <buf+206> "1-82290@127.0.0.1\r\nRoute: <sip:127.0.0.1;lr;ftag=1;did=57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: Performance Test\r\nContent-Length: 0\r\n\r\n", len = 17}
        ftag = {
          s = 0x55ebe8597f36 <buf+150> "1\r\nTo: sut <sip:service@127.0.0.1:5060>;tag=1\r\nCall-ID: 1-82290@127.0.0.1\r\nRoute: <sip:127.0.0.1;lr;ftag=1;did=57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: P"..., len = 1}
        ttag = {
          s = 0x55ebe8597f62 <buf+194> "1\r\nCall-ID: 1-82290@127.0.0.1\r\nRoute: <sip:127.0.0.1;lr;ftag=1;did=57e.1e128ca>\r\nCSeq: 2 BYE\r\nContact: sip:sipp@127.0.0.1:5090\r\nMax-Forwards: 69\r\nSubject: Performance Test\r\nContent-Length: 0\r\n\r\n", len = 1}
        h_entry = <optimized out>
        h_id = <optimized out>
        new_state = 5
        old_state = 4
        unref = 2
        event = <optimized out>

Describe the traffic that generated the bug

SIPREC call

To Reproduce

  1. Configure OpenSIPS with SIPREC
  2. Establish a call with rtp_relay_engage("rtpproxy")
  3. Add siprec_start_recording in the main route
  4. A basic SIPREC session established.
  5. Send a BYE from caller to tear down the dialog.
  6. OpenSIPS crashes in rtp_relay_delete with ftag=[]
    Relevant System Logs
DBG:rtp_relay:rtp_relay_delete: callid=[1-82290@127.0.0.1] ftag=[] ttag=[1] ctx-flags=[] delete-flags=[]
CRITICAL:core:sig_usr: segfault in process pid: 82133, id: 6
DBG:core:restore_segv_handler: restoring SIGSEGV handler...
DBG:core:restore_segv_handler: successfully restored system SIGSEGV handler

OS/environment information

  • Operating System:
  • OpenSIPS installation:
  • other relevant information:

Root Cause Analysis

Looking at rtp_relay_delete_ctx, the fix is straightforward — assign info.from_tag from ctx->from_tag, mirroring how callid and to_tag are handled. The comment in your code already hints at this.

static void rtp_relay_delete_ctx(struct rtp_relay_ctx *ctx, struct rtp_relay_sess *sess, int leg)
{
 struct rtp_relay_session info;
 memset(&info, 0, sizeof info);

 info.callid = &ctx->callid;
 if (!info.callid->len)
  info.callid = &ctx->dlg_callid;

 if (ctx->from_tag.len)
  info.from_tag = &ctx->from_tag;

 info.to_tag = &ctx->to_tag;
 info.branch = RTP_RELAY_ALL_BRANCHES;
 rtp_relay_delete(&info, ctx, sess, leg);
}

This avoids the need to pass msg through the call chain. Since rtp_relay_delete_ctx is called on BYE (dialog teardown), ctx->from_tag should already be populated from the initial INVITE flow via rtp_relay_fill_dlg. The from_tag check in rtpproxy_fill_call_args (if (!sess->from_tag)) will then skip the get_from_tag(sess->msg, ...) call that would fail due to info.msg being NULL.

Why info.msg is NULL in rtp_relay_delete_ctx
In rtp_relay_delete_ctx, the info struct is zeroed out with memset(&info, 0, sizeof info), and info.msg is never assigned afterwards. Unlike other call paths (e.g., rtp_relay_indlg_tm_req which sets info.msg = p->req), this function only populates callid, to_tag, and branch — leaving info.msg = NULL.
When rtp_relay_delete is called with this info, it eventually reaches rtpproxy_fill_call_args in the rtpproxy module. There, the check:

if (!sess->from_tag) {
    if (get_from_tag(sess->msg, &args->from_tag) == -1 || args->from_tag.len == 0) {
        LM_ERR("can't get From tag\n");
        return 0;
    }
}

tries to extract the from_tag from sess->msg, which is NULL (since info.msg was never set), causing a crash or silent failure.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions