Skip to content

sdp_ops: fix body-lump offsets once $sdp owns the body (SIGABRT/SIGSEGV) - #4237

Open
Lt-Flash wants to merge 2 commits into
OpenSIPS:masterfrom
Lt-Flash:fix/sdp-ops-body-ownership
Open

sdp_ops: fix body-lump offsets once $sdp owns the body (SIGABRT/SIGSEGV)#4237
Lt-Flash wants to merge 2 commits into
OpenSIPS:masterfrom
Lt-Flash:fix/sdp-ops-body-ownership

Conversation

@Lt-Flash

@Lt-Flash Lt-Flash commented Sep 3, 2026

Copy link
Copy Markdown

Fixes #4135.

Two commits: the crash fix first, then a small parser fix found on the same path.

1. Body-lump offsets once $sdp owns the body

Once $sdp / $sdp.line / $sdp.stream / $sdp.session has touched a message, get_body() returns a pointer into sdp_ops' own pkg buffer rather than into msg->buf. Every body editor that then anchors a lump with body.s - msg->buf is doing pointer arithmetic between two unrelated allocations:

  • del_lump()'s bounds check aborts the worker — the reporter's SIGABRT, del_lump: offset exceeds message size (-2036890104 > 1068) — via rtp_relay_engage(), rtpengine_offer()/rtpengine_answer() (sync and async paths), mediaproxy, textops search_append_body(), sipmsgops codec editing.
  • apply_msg_changes() in msg_translator.c — a branch written for sdp_ops — makes the same subtraction and then memcpy()s a few GB: SIGSEGV in build_req_buf_from_sip_req (the reporter's second backtrace). This one needs no module at all:
$sdp = $sdp;
t_relay();

crashes a stock build.

Fix. sdp_ops gets a small API extracted from pv_set_sdp()sdp_ops_set_body(), sdp_ops_set_null_body(), sdp_ops_splice_body() (offsets relative to the current body buffer) — and each affected call site goes through it when have_sdp_ops(msg) is true; the lump path is untouched otherwise. apply_msg_changes() recovers the received body position the way calculate_body_diff() already does, so the function that sizes the buffer and the one that fills it agree. codecs.c fails cleanly with an error instead of computing an invalid offset — its incremental multi-lump editing has no sdp_ops equivalent.

2. $sdp.* names ending with an escape

pv_parse_sdp_line_name() / pv_parse_sdp_stream_name() dropped the last name segment when the name ends with an escape (the manual's own a=rtpmap:101/telephone-event\/), silently turning a token match into a whole-line match — on reads and writes.

Verification

A local reproduction rig: the reporter's script shape ($sdp.line reads + rtpengine_offer()) and the module-free $sdp = $sdp; t_relay() both crash on the unpatched build and relay a well-formed message with the fix (a downstream sink validates Content-Length against the body). Builds clean with -Wredundant-decls -Wold-style-definition -Wmissing-field-initializers -Werror on current master.

Not in this PR

modules/sngtc has the same pattern at four sites but cannot be built without the Sangoma library, so it is left as is and named here. The token-write side of the same report ($sdp.line(o=/[5]) = "..." being a silent no-op) is a separate change and will follow as its own PR.

Yury Kirsanov added 2 commits September 3, 2026 20:12
Once $sdp / $sdp.line / $sdp.stream / $sdp.session has touched a message,
get_body() returns a pointer into sdp_ops' own pkg buffer (ops->sdp or
ops->rebuilt_sdp), not into msg->buf. Every body editor that then computes
"body.s - msg->buf" to anchor a lump feeds garbage pointer arithmetic to
del_lump()/insert_new_lump(): del_lump's bounds check aborts the worker
(SIGABRT, "offset exceeds message size"), and apply_msg_changes() in
msg_translator.c - a branch written FOR sdp_ops - does the same
subtraction and then memcpy()s with a size of a few GB (SIGSEGV in
build_req_buf_from_sip_req). The second one needs no module at all:

    $sdp = $sdp;
    t_relay();

crashes a stock build. The first one fires with rtp_relay_engage(),
rtpengine_offer()/_answer() (sync and async reply paths), mediaproxy,
textops' search_append_body() and sipmsgops' codec editing.

Fix: sdp_ops grows a small API extracted from pv_set_sdp() -
sdp_ops_set_body(), sdp_ops_set_null_body() and sdp_ops_splice_body(),
the latter taking offsets relative to the CURRENT body buffer - and every
affected call site goes through it when have_sdp_ops(msg) is true, leaving
the lump path untouched otherwise. apply_msg_changes() recovers the
received body position the same way calculate_body_diff() already does
(NULL msg->sdp_ops around get_body()), so the two stay in agreement -
one sizes the buffer, the other fills it. codecs.c, whose incremental
multi-lump editing has no sdp_ops equivalent, now fails cleanly with an
error instead of computing an invalid offset.

modules/sngtc carries the same "body.s - msg->buf" pattern but is not
changed here - it cannot be built without the Sangoma library.

Fixes OpenSIPS#4135
…scape

pv_parse_sdp_line_name() (which also serves $sdp.session) and
pv_parse_sdp_stream_name() lost the final segment of the name whenever it
ends with an escape, e.g. the manual's own
"$sdp.line(a=rtpmap:101/telephone-event\/)": unescaping shortens in.len
and rewinds i, so on the last character the loop exits on the shortened
length and the in-loop "(i+1) == in.len" assignment of the last segment
never runs. The token prefix was silently dropped and the name degraded
into a whole-line match - on reads, and on writes, which then replaced
the entire line with the value.

Assign whatever trails the last separator after the loop instead, guarded
by a flag that the "[" with no following "/" break path clears.

Related to OpenSIPS#4135
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] - a second SDP rebuild terminates a worker, causing a complete restart of opensips

1 participant