b2b_entities: fix crash calling b2b_init_request from async resume route #3822
+8
−0
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a crash (
fm_free: freeing dangling pkg pointer/qm_free_dbg: bad pointer (out of memory block\!) - aborting) whenb2b_init_request()is called from an async resume route (e.g. afterrest_post()). The worker process aborts with signal 6 (SIGABRT) and a core dump is generated, taking down the entire OpenSIPS instance.Details
When an initial INVITE is processed with an async operation (e.g.
async(rest_post(...), resume_route)), the TM module:t_newtran(), including all parsed headers and any lumps added before the async call (e.g. fromrecord_route(),fix_nated_contact(),append_hf(), etc.)t_resume_async_request()intm/async.ccallsfake_req()(tm/t_msgbuilder.h:194) to build a faked SIP message for the resume routefake_req()doesmemcpy(faked_req, shm_msg, sizeof(struct sip_msg))at line 202 — this copies the entiresip_msgstruct, meaning the faked request'smsg->headers,msg->add_rm, andmsg->body_lumpspointers all point into SHM memory (they are the same SHM pointers from the transaction's stored request)fake_req()then PKG-duplicates only specific fields (new_uri,dst_uri,path_vec,set_global_address,set_global_port) and setsfaked_req->msg_flags |= FL_TM_FAKE_REQat line 211When the resume route calls
b2b_init_request(), the script-level handlerb2bl_script_init_request()(b2b_logic/logic.c:3228) callsb2b_api.apply_lumps(msg)directly at line 3245 — before any B2B entities are created. This dispatches tob2b_apply_lumps()inb2b_entities/dlg.c, where the following crash sequence occurs:b2b_apply_lumps()checksif(\!msg->body_lumps && \!msg->add_rm) return 0;— if any module added lumps before the async call, these SHM lump pointers are non-NULL, so execution continuesbuild_req_buf_from_sip_req()processes the lumps to build a new bufferfree_sip_msg(msg)is called to free the old message structurefree_sip_msg()(parser/msg_parser.c:965), the call tofree_hdr_field_lst(msg->headers)at line 980 walks the parsed header linked list and callspkg_free()on each header nodepkg_free()on SHM pointers triggers the memory allocator's safety check and aborts the processTM's own
free_faked_req()(tm/t_msgbuilder.h:345) is designed to handle this correctly — it carefully frees only the PKG-duplicated fields and never callsfree_hdr_field_lst()on the headers. The b2b_entities module'sb2b_apply_lumps()was missing this awareness.The crash is deterministic: it occurs on every call to
b2b_init_request()from an async resume route, provided any module added lumps to the request before the async call. Common lump-producing functions includerecord_route(),fix_nated_contact(),append_hf(),remove_hf(), and many others. In production configurations, lumps are almost always present.Note that
b2b_apply_lumps()is called from 6 sites — not onlyb2bl_script_init_request()(logic.c:3245) but alsob2bl_script_bridge()(bridging.c:2290) and 4 internal call sites withindlg.citself (lines 1103, 3306, 3373, 3755). The fix in the function body protects all of them.Affected versions: The bug exists in all versions where
b2b_apply_lumps()exists alongside TM async support. Confirmed on 3.6.2 (reporter) and 4.0.0-dev (our testing).Solution
Add a guard at the top of
b2b_apply_lumps()that checks theFL_TM_FAKE_REQflag and returns early:This mirrors TM's own approach —
FL_TM_FAKE_REQ(1<<18, defined inparser/msg_parser.h:121) is already set byfake_req()attm/t_msgbuilder.h:211precisely to mark faked requests. TM'sfree_faked_req()uses this same awareness to avoid freeing SHM headers.Skipping lump application is safe for faked requests because:
b2b_apply_lumps()returning 0 simply means "no modifications were made", which all 6 callers already handleReproduction
Tested on OpenSIPS 4.0.0-dev (x86_64/linux,
DBG_MALLOCenabled) with this minimal config:A simple Python HTTP server on port 8899 with a 100ms delay ensures the async machinery activates. A SIP INVITE sent via
nc -utriggers the flow.record_route)CRITICAL: qm_free_dbg: bad pointer (out of memory block\!) - aborting, worker killed by signal 6, core dump generated, entire OpenSIPS instance terminatesrecord_route)b2b_init_requestcompletes successfully, B2B session established, process stablerecord_route)b2b_apply_lumpsreturns early at the\!msg->body_lumps && \!msg->add_rmcheck, confirming the lump-dependent triggerCompatibility
No backward compatibility issues. The fix only adds an early-return guard for a specific message type (TM faked requests) that was previously crashing. No behavior change for normal (non-faked) SIP messages. The
FL_TM_FAKE_REQflag is defined in core headers (parser/msg_parser.h) and is available to all modules.Closing issues
Closes #3796