Commit 455d691d0e for asterisk.org

commit 455d691d0ea10c603f63248a8327abcdbf29b626
Author: phoneben <3232963@gmail.com>
Date:   Tue Oct 13 13:33:01 2026 +0300

    res_pjsip_caller_id: Avoid channel access outside session serializer

    res_pjsip_caller_id: Avoid channel access outside session serializer

    **Issue:**

    During SIP response retransmissions, `caller_id_outgoing_response()` may execute on the PJSIP monitor thread, outside the session serializer.

    If a channel masquerade changes `session->channel` between the lock and unlock operations, the original channel mutex may remain locked, potentially causing a deadlock during `PickupChan()`.

    **Fix:**

    Add a serializer check using `ast_taskpool_serializer_get_current()` to prevent accessing `session->channel` outside its session serializer, following the existing pattern in `res_pjsip_rfc3326.c`.

    **AI assistance:** ChatGPT assisted with identifying the issue and drafting the PR description.

    Resolves: #2224

diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c
index 2289ab4db1..72a347f879 100644
--- a/res/res_pjsip_caller_id.c
+++ b/res/res_pjsip_caller_id.c
@@ -34,6 +34,7 @@
 #include "asterisk/module.h"
 #include "asterisk/callerid.h"
 #include "asterisk/conversions.h"
+#include "asterisk/taskpool.h"

 static int extract_oli(const pjsip_param *param_list, char *buf, size_t len)
 {
@@ -590,7 +591,18 @@ static void caller_id_outgoing_response(struct ast_sip_session *session, pjsip_t
 	struct ast_party_id effective_id;
 	struct ast_party_id connected_id;

-	if (!session->channel
+	/*
+	 * Outgoing response callbacks may execute on the PJSIP monitor
+	 * thread during retransmissions, outside the session serializer.
+	 * The channel pointer can change during a masquerade, potentially
+	 * causing a channel mutex to remain locked.
+	 *
+	 * Retransmitted responses already contain the caller ID information
+	 * added when the response was first sent, so skipping this callback
+	 * outside the serializer does not change the response contents.
+	 */
+	if (session->serializer != ast_taskpool_serializer_get_current()
+		|| !session->channel
 		|| (!session->endpoint->id.send_connected_line
 			&& session->inv_session
 			&& session->inv_session->state >= PJSIP_INV_STATE_EARLY)) {