Skip to content

jsonrpc, rtpengine, aaa_diameter, janus: fix cJSON NULL derefs and memory leaks#3850

Open
dondetir wants to merge 4 commits intoOpenSIPS:masterfrom
dondetir:fix/cjson-null-deref-leak-audit
Open

jsonrpc, rtpengine, aaa_diameter, janus: fix cJSON NULL derefs and memory leaks#3850
dondetir wants to merge 4 commits intoOpenSIPS:masterfrom
dondetir:fix/cjson-null-deref-leak-audit

Conversation

@dondetir
Copy link
Copy Markdown

Summary

Fix NULL pointer dereferences and memory leaks caused by unchecked cJSON_Print() / cJSON_PrintUnformatted() return values across four modules, found during a systematic audit following the janus leak fixes in commit f9fb3ea.

Details

  • Type: Bug fix
  • Motivation: Commit f9fb3ea fixed several pkg memory leaks in the janus module where cJSON_Print() return values were not freed. A systematic audit of all cJSON usage across modules revealed the same class of issue in three additional modules, plus one remaining site in janus that was missed:
  1. jsonrpc (jsonrpc_handle_cmd()) — cJSON_Print(aux) can return NULL on allocation failure. The return is passed directly to strlen(), causing a crash. Two separate call sites affected. Additionally, the cJSON_Parse() result (obj) is never freed with cJSON_Delete(), leaking the entire parsed JSON tree on every JSON-RPC command.

  2. rtpengine (rtpengine_raise_event()) — cJSON_PrintUnformatted(param) can return NULL. Both strlen() and cJSON_PurgeString() on the next lines would crash on NULL.

  3. aaa_diameter (dm_receive_req()) — cJSON_PrintUnformatted(avps) is passed directly to init_str(), which calls strlen() internally, crashing on NULL. The module uses cJSON_InitHooks(&shm_mem_hooks) so cJSON allocates from shared memory.

  4. janus (populate_janus_handler_id()) — Four calls to cJSON_Print(request) are embedded directly in LM_ERR() format arguments. The pkg-allocated return values are never stored or freed, leaking ~100-500 bytes per error path hit. This was missed by the fix in f9fb3ea which addressed similar leaks in other janus functions.

  • Affected scenarios: All bugs trigger on memory allocation failure during cJSON serialization. The janus leaks occur on every error path hit regardless of memory pressure.
  • Generic problem — not specific to any particular UAC or scenario.

Solution

  • jsonrpc: Added NULL checks after both cJSON_Print() calls. Added cJSON_Delete(obj) to the cleanup path to fix the object leak.
  • rtpengine: Added NULL check before strlen() / cJSON_PurgeString(). On failure, the parameter is skipped and the loop continues.
  • aaa_diameter: Replaced init_str() call with explicit NULL check and manual str assignment. On failure, goto error follows the existing cleanup pattern (cJSON_PurgeString + cJSON_Delete + cJSON_InitHooks(NULL)).
  • janus: Store cJSON_Print() result in a local variable, use it in the log message, then free it. Added NULL guards before pkg_free() to match the pattern established in f9fb3ea.
  • Remaining concerns: None. All fixes are minimal and follow established patterns in each module.

Compatibility

  • No backward compatibility issues
  • No migration needed
  • No SIP interoperability impact
  • These are purely defensive NULL checks and leak fixes on error/serialization paths

Closing Issues

N/A — found via code audit following f9fb3ea.

cJSON_Print() can return NULL on allocation failure.  The existing code
passes the return value directly to strlen() without a NULL check,
causing a crash on two separate code paths (error and result handling).

Add NULL checks after both cJSON_Print() calls.

Additionally, the cJSON tree allocated by cJSON_Parse() at the start of
the function is never freed.  Add cJSON_Delete(obj) to the cleanup path.

Found during a systematic audit of cJSON return value handling across
modules, following the janus leak fixes in commit f9fb3ea.
In rtpengine_raise_event(), cJSON_PrintUnformatted() can return NULL on
allocation failure.  The return value is passed directly to strlen() and
then to cJSON_PurgeString(), both of which will crash on a NULL pointer.

Add a NULL check before using the return value, and skip the parameter
on failure.

Found during a systematic audit of cJSON return value handling across
modules, following the janus leak fixes in commit f9fb3ea.
cJSON_PrintUnformatted() can return NULL on allocation failure (using shm
hooks).  The return value is passed directly to init_str(), which calls
strlen() on it, causing a crash.

Replace the init_str() call with an explicit NULL check and manual
assignment, following the existing error-handling pattern in the function
(goto error, which properly cleans up via cJSON_Delete and
cJSON_PurgeString).

Found during a systematic audit of cJSON return value handling across
modules, following the janus leak fixes in commit f9fb3ea.
The janus module uses cJSON_InitHooks() to route cJSON allocations
through pkg_malloc.  In populate_janus_handler_id(), four calls to
cJSON_Print(request) are embedded directly in LM_ERR() format arguments.
The pkg-allocated return values are never stored or freed, leaking
~100-500 bytes per error path hit.

Store the cJSON_Print() result, use it in the log message, and free it
afterward.  Also handle the case where cJSON_Print() returns NULL.

This follows up on the janus leak fixes in commit f9fb3ea, which
addressed similar leaks in janus_raise_event(),
handle_janus_json_request(), and janus_ipc_send_request() but missed
populate_janus_handler_id().
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.

1 participant