From d96b6a4a8f97fe2bead4099c3ad9dbd16276ae40 Mon Sep 17 00:00:00 2001
From: Andrey Volk <andywolk@gmail.com>
Date: Sat, 23 Jul 2022 22:07:40 +0300
Subject: [PATCH] [Core] Fix possible race condition between locking a session
 and reading it's flags in switch_core_session_read_lock() and
 switch_core_session_read_lock_hangup().

---
 src/switch_core_rwlock.c | 44 +++++++++++++++++++++-------------------
 1 file changed, 23 insertions(+), 21 deletions(-)

diff --git a/src/switch_core_rwlock.c b/src/switch_core_rwlock.c
index 61c9ca45b9..69e188ed79 100644
--- a/src/switch_core_rwlock.c
+++ b/src/switch_core_rwlock.c
@@ -85,9 +85,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_lock(switch_core_sessio
 	switch_status_t status = SWITCH_STATUS_FALSE;
 
 	if (session->rwlock) {
-		if (switch_test_flag(session, SSF_DESTROYED) || switch_channel_down_nosig(session->channel)) {
-			status = SWITCH_STATUS_FALSE;
-			if (switch_thread_rwlock_tryrdlock(session->rwlock) == SWITCH_STATUS_SUCCESS) {
+		if ((status = switch_thread_rwlock_tryrdlock(session->rwlock)) == SWITCH_STATUS_SUCCESS) {
+			if (switch_test_flag(session, SSF_DESTROYED) || switch_channel_down_nosig(session->channel)) {
+				status = SWITCH_STATUS_FALSE;
 				if (switch_channel_test_flag(session->channel, CF_THREAD_SLEEPING)) {
 #ifdef SWITCH_DEBUG_RWLOCKS
 					switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Ping thread\n",
@@ -95,18 +95,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_lock(switch_core_sessio
 #endif
 					switch_core_session_wake_session_thread(session);
 				}
+
+#ifdef SWITCH_DEBUG_RWLOCKS
+				switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock FAIL\n",
+								  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
+#endif
 				switch_thread_rwlock_unlock(session->rwlock);
+			} else {
+#ifdef SWITCH_DEBUG_RWLOCKS
+				switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock ACQUIRED\n",
+								  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
+#endif
 			}
-#ifdef SWITCH_DEBUG_RWLOCKS
-			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock FAIL\n",
-							  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
-#endif
-		} else {
-			status = (switch_status_t) switch_thread_rwlock_tryrdlock(session->rwlock);
-#ifdef SWITCH_DEBUG_RWLOCKS
-			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock ACQUIRED\n",
-							  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
-#endif
 		}
 	}
 
@@ -123,18 +123,20 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_lock_hangup(switch_core
 	switch_status_t status = SWITCH_STATUS_FALSE;
 
 	if (session->rwlock) {
-		if (switch_test_flag(session, SSF_DESTROYED) || switch_channel_get_state(session->channel) >= CS_DESTROY) {
-			status = SWITCH_STATUS_FALSE;
+		if ((status = switch_thread_rwlock_tryrdlock(session->rwlock)) == SWITCH_STATUS_SUCCESS) {
+			if (switch_test_flag(session, SSF_DESTROYED) || switch_channel_get_state(session->channel) >= CS_DESTROY) {
+				status = SWITCH_STATUS_FALSE;
 #ifdef SWITCH_DEBUG_RWLOCKS
-			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock FAIL\n",
-							  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
+				switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock FAIL\n",
+								  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
 #endif
-		} else {
-			status = (switch_status_t) switch_thread_rwlock_tryrdlock(session->rwlock);
+				switch_thread_rwlock_unlock(session->rwlock);
+			} else {
 #ifdef SWITCH_DEBUG_RWLOCKS
-			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock ACQUIRED\n",
-							  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
+				switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_core_session_get_uuid(session), SWITCH_LOG_ERROR, "%s %s Read lock ACQUIRED\n",
+								  switch_core_session_get_uuid(session), switch_channel_get_name(session->channel));
 #endif
+			}
 		}
 	}