From: Alexei Gradinari Date: Wed, 7 Jan 2026 20:39:05 +0000 (-0500) Subject: res_pjsip_pubsub: Fix ao2 reference leak of subscription tree in ast_sip_subscription X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=59b281bdd875124877d9eea8b7d5c8ff36a5b931;p=thirdparty%2Fasterisk.git res_pjsip_pubsub: Fix ao2 reference leak of subscription tree in ast_sip_subscription allocate_subscription() increments the ao2 reference count of the subscription tree, but the reference was not consistently released during subscription destruction, resulting in leaked sip_subscription_tree objects. This patch makes destroy_subscription() responsible for releasing sub->tree, removes ad-hoc cleanup in error paths, and guards tree cleanup to ensure refcount symmetry and correct ownership. Fixes: #1703 --- diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 6ae0e3ed7b..644b54238f 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1446,6 +1446,12 @@ static void destroy_subscription(struct ast_sip_subscription *sub) ao2_cleanup(sub->datastores); ast_json_unref(sub->persistence_data); ast_free(sub->display_name); + if (sub->tree) { + /* Clear tree before cleanup to avoid re-entrant destruction */ + struct sip_subscription_tree *tree = sub->tree; + sub->tree=NULL; + ao2_cleanup(tree); + } ast_free(sub); } @@ -1561,10 +1567,7 @@ static struct ast_sip_subscription *create_virtual_subscriptions(const struct as if (AST_VECTOR_APPEND(&sub->children, child)) { ast_debug(1, "Child subscription to resource %s could not be appended\n", child_node->resource); - destroy_subscription(child); - /* Have to release tree here too because a ref was added - * to child that destroy_subscription() doesn't release. */ - ao2_cleanup(tree); + destroy_subscriptions(child); } } @@ -1637,7 +1640,12 @@ void ast_sip_subscription_destroy(struct ast_sip_subscription *sub) { ast_debug(3, "Removing subscription %p '%s->%s' reference to subscription tree %p\n", sub, ast_sorcery_object_get_id(sub->tree->endpoint), sub->resource, sub->tree); - ao2_cleanup(sub->tree); + if (sub->tree) { + /* Clear tree before cleanup to avoid re-entrant destruction */ + struct sip_subscription_tree *tree = sub->tree; + sub->tree = NULL; + ao2_cleanup(tree); + } } static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pjsip_dialog *dlg)