Skip to content

aaa_diameter: fix SHM cJSON leaks and double-free found after 1e8001fa0#3882

Open
dondetir wants to merge 2 commits intoOpenSIPS:masterfrom
dondetir:fix/aaa-diameter-cjson-leaks
Open

aaa_diameter: fix SHM cJSON leaks and double-free found after 1e8001fa0#3882
dondetir wants to merge 2 commits intoOpenSIPS:masterfrom
dondetir:fix/aaa-diameter-cjson-leaks

Conversation

@dondetir
Copy link
Copy Markdown
Contributor

Summary

Fix SHM cJSON memory leaks and a heap double-free in the aaa_diameter module, found during a systematic audit of dm_send_request() paths following commit 1e8001fa0.

Details

  • Type: Bug fix
  • Motivation: Commit 1e8001fa0 established that _dm_release_message_response() is the only correct path for freeing the SHM-backed cond->rpl.json cJSON tree. A systematic audit of all callers revealed two paths where the release was silently skipped, plus a related double-free in the AVP parser:
  1. dm_send_request() — SHM leak when no output PV (aaa_diameter.c:336–341): _dm_release_message_response() was called only inside if (rpl_avps_pv). When the SIP script calls the function without an output PV argument, the SHM cJSON reply tree leaked on every Diameter response.

  2. dm_send_request_async_reply() — SHM leak when no output PV or on read() failure (aaa_diameter.c:524–525): The release was guarded by if (rpl_avps), which was NULL both when no output PV was configured (the async counterpart of bug 1) and on the read() failure path — even though the Diameter reply callback had already populated cond->rpl.json.

  3. dm_avps2json() — SHM heap double-free (dm_impl.c:525–536): cJSON_AddItemToArray(avps, item) transfers ownership of item to avps, but item was not cleared afterward. Any subsequent FD_CHECK_GT failure in the loop (fd_msg_browse, fd_msg_avp_hdr, or fd_dict_getval) jumps to out:, which calls cJSON_Delete(item) — double-freeing SHM memory and corrupting the shared heap across all worker processes.

  • Affected scenarios: Bugs 1 and 2 affect any dm_send_request() call (sync or async) without an output PV, leaking shared memory proportional to request volume. Bug 3 triggers on any freeDiameter library error during AVP iteration after at least one AVP has been successfully parsed.
  • Generic problem — not specific to any particular deployment configuration.

Solution

  • aaa_diameter.c (Bugs 1 & 2): Moved _dm_release_message_response() outside the if (rpl_avps_pv) / if (rpl_avps) guards in both dm_send_request() and dm_send_request_async_reply(). _dm_release_message_response() safely handles a NULL rpl_avps argument (cJSON_PurgeString is a no-op on NULL, and cond->rpl.json is checked before deletion), so the unconditional call is safe in all cases.

  • dm_impl.c (Bug 3): Added item = NULL immediately after cJSON_AddItemToArray(avps, item). This clears the pointer after ownership transfer, making any subsequent cJSON_Delete(item) at out: a safe no-op (cJSON_Delete(NULL) is defined to do nothing).

  • Remaining concerns: None.

Compatibility

  • No backward compatibility issues
  • No migration needed
  • No SIP interoperability impact

Closing Issues

N/A — found during a systematic audit of dm_send_request() paths following commit 1e8001fa0.

_dm_release_message_response() is the only function that frees the
SHM-backed cJSON reply tree (cond->rpl.json).  In dm_send_request(),
the release call was gated inside "if (rpl_avps_pv)", so every call
without an output PV leaked the entire SHM cJSON tree.

The same issue existed in dm_send_request_async_reply(): the release
was guarded by "if (rpl_avps)", which was NULL both when no output PV
was configured and on the read() failure path — even though the reply
callback had already populated cond->rpl.json.

_dm_release_message_response() safely handles a NULL rpl_avps argument
(cJSON_PurgeString is a no-op on NULL), so removing both guards is safe.

Found during a systematic audit of dm_send_request() paths following
commit 1e8001f.
After cJSON_AddItemToArray(avps, item) transfers ownership of item to
avps, item is not cleared.  Any subsequent FD_CHECK_GT failure in the
same or next loop iteration jumps to the out: label, which calls
cJSON_Delete(item) — freeing memory already owned by avps.

This double-free corrupts the SHM heap, affecting all worker processes.
The affected paths include:
  - FD_CHECK_GT(fd_msg_browse()) at the skip: label (next-iteration
    advance)
  - FD_CHECK_GT(fd_msg_avp_hdr()) and FD_CHECK_GT(fd_dict_getval())
    at the start of the next iteration

Fix: clear item immediately after the ownership transfer so that any
later cJSON_Delete(item) at out: is a safe no-op.

Found during a systematic audit following commit 1e8001f.
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.

2 participants