]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
chan_websocket: Add locking in send_event and check for NULL websocket handle.
authorGeorge Joseph <gjoseph@sangoma.com>
Wed, 10 Dec 2025 17:45:24 +0000 (10:45 -0700)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Mon, 15 Dec 2025 16:01:31 +0000 (16:01 +0000)
On an outbound websocket connection, when the triggering caller hangs up,
webchan_hangup() closes the outbound websocket session and sets the websocket
session handle to NULL.  If the hangup happened in the tiny window between
opening the outbound websocket connection and before read_thread_handler()
was able to send the MEDIA_START message, it could segfault because the
websocket session handle was NULL.  If it didn't actually segfault, there was
also the possibility that the websocket instance wouldn't get cleaned up which
could also cause the channel snapshot to not get cleaned up.  That could
cause memory leaks and `core show channels` to list phantom WebSocket
channels.

To prevent the race, the send_event() macro now locks the websocket_pvt
instance and checks the websocket session handle before attempting to send
the MEDIA_START message.

Resolves: #1643
Resolves: #1645

channels/chan_websocket.c

index 9b1db22298afbcdf2aca5b99567de000fc33adad..4d86b86e533c9af36888f94b1d83ea0093805597 100644 (file)
@@ -416,7 +416,8 @@ static __attribute__ ((format (gnu_printf, 2, 3))) char *_create_event_ERROR(
 ({ \
        int _res = -1; \
        char *_payload = _create_event_ ## _event(_instance, ##__VA_ARGS__); \
-       if (_payload) { \
+       ao2_lock(instance); \
+       if (_payload && _instance->websocket) { \
                _res = ast_websocket_write_string(_instance->websocket, _payload); \
                if (_res != 0) { \
                        ast_log(LOG_ERROR, "%s: Unable to send event %s\n", \
@@ -427,6 +428,7 @@ static __attribute__ ((format (gnu_printf, 2, 3))) char *_create_event_ERROR(
                }\
                ast_free(_payload); \
        } \
+       ao2_unlock(instance); \
        (_res); \
 })