]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Merge commit from fork
authorDmitry Verenitsin <morbit85@gmail.com>
Tue, 26 May 2026 19:24:48 +0000 (00:24 +0500)
committerGitHub <noreply@github.com>
Tue, 26 May 2026 19:24:48 +0000 (22:24 +0300)
`process_jrpc()` called `set_session_id()` before `check_auth()`, so an
unauthenticated client could insert its jsock into `jsock_hash` under a
foreign `sessid` and have `attach_jsock()` evict the prior owner
(`verto.punt` + `detach_calls()` + `drop=1`) with no identity check.

Move the bind past the auth gate; `JPFLAG_INIT` now means "jsock is
bound", not "first frame seen". Additionally, `attach_jsock()` refuses
the bind when prior and new jsock are authed under different `uid`s,
replying `CODE_AUTH_FAILED` "Session in use". Same-uid reconnect and
no-auth profile binds are unchanged.

src/mod/endpoints/mod_verto/mod_verto.c

index c2464d9023db3896dacb4519385c420193a1c00d..f2233df73a8acbf2c735767e97acd62415e34795 100644 (file)
@@ -1272,10 +1272,11 @@ static jsock_t *get_jsock(const char *uuid)
 
 static void tech_reattach(verto_pvt_t *tech_pvt, jsock_t *jsock);
 
-static void attach_jsock(jsock_t *jsock)
+static switch_bool_t attach_jsock(jsock_t *jsock)
 {
        jsock_t *jp;
        int proceed = 1;
+       switch_bool_t result = SWITCH_TRUE;
 
        switch_mutex_lock(verto_globals.jsock_mutex);
 
@@ -1284,6 +1285,17 @@ static void attach_jsock(jsock_t *jsock)
        if ((jp = switch_core_hash_find(verto_globals.jsock_hash, jsock->uuid_str))) {
                if (jp == jsock) {
                        proceed = 0;
+               } else if (!zstr(jp->uid) && !zstr(jsock->uid) && strcmp(jp->uid, jsock->uid)) {
+                       /* Refuse cross-identity takeover when both jsocks are authenticated under different uids.
+                        * Clear uuid_str and set nodelete to prevent any uuid_str-keyed teardown
+                        * (detach_jsock, del_jsock, detach_calls) from touching jp. */
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+                               "User %s blocked from taking over session %s owned by %s\n",
+                               jsock->uid, jsock->uuid_str, jp->uid);
+                       jsock->nodelete = 1;
+                       jsock->uuid_str[0] = '\0';
+                       proceed = 0;
+                       result = SWITCH_FALSE;
                } else {
                        cJSON *params = NULL;
                        cJSON *msg = NULL;
@@ -1304,6 +1316,7 @@ static void attach_jsock(jsock_t *jsock)
        }
 
        switch_mutex_unlock(verto_globals.jsock_mutex);
+       return result;
 }
 
 static void detach_jsock(jsock_t *jsock)
@@ -1482,10 +1495,8 @@ static void process_jrpc_response(jsock_t *jsock, cJSON *json)
 {
 }
 
-static void set_session_id(jsock_t *jsock, const char *uuid)
+static switch_bool_t set_session_id(jsock_t *jsock, const char *uuid)
 {
-       //cJSON *params, *msg = jrpc_new(0);
-
        if (!zstr(uuid)) {
                switch_set_string(jsock->uuid_str, uuid);
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s re-connecting session %s\n", jsock->name, jsock->uuid_str);
@@ -1494,8 +1505,7 @@ static void set_session_id(jsock_t *jsock, const char *uuid)
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s new RPC session %s\n", jsock->name, jsock->uuid_str);
        }
 
-       attach_jsock(jsock);
-
+       return attach_jsock(jsock);
 }
 
 static cJSON *process_jrpc(jsock_t *jsock, cJSON *json)
@@ -1515,11 +1525,6 @@ static cJSON *process_jrpc(jsock_t *jsock, cJSON *json)
                sessid = cJSON_GetObjectCstr(params, "sessid");
        }
 
-       if (!switch_test_flag(jsock, JPFLAG_INIT)) {
-               set_session_id(jsock, sessid);
-               switch_set_flag(jsock, JPFLAG_INIT);
-       }
-
        if (zstr(version) || strcmp(version, "2.0")) {
                reply = jrpc_new(0);
                jrpc_add_error(reply, CODE_INVALID, "Invalid message", id);
@@ -1546,6 +1551,17 @@ static cJSON *process_jrpc(jsock_t *jsock, cJSON *json)
                switch_set_flag(jsock, JPFLAG_AUTHED);
        }
 
+       /* Bind only after the auth gate — attach_jsock()'s eviction
+        * must not be reachable pre-auth. */
+       if (!switch_test_flag(jsock, JPFLAG_INIT)) {
+               if (!set_session_id(jsock, sessid)) {
+                       jrpc_add_error(reply, CODE_AUTH_FAILED, "Session in use", id);
+                       jsock->drop = 1;
+                       goto end;
+               }
+               switch_set_flag(jsock, JPFLAG_INIT);
+       }
+
        if (!method || !(func = jrpc_get_func(jsock, method))) {
                jrpc_add_error(reply, -32601, "Invalid Method, Missing Method or Permission Denied", id);
        } else {