]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip_pubsub: Fix ao2 reference leak of subscription tree in ast_sip_subscription
authorAlexei Gradinari <alex2grad@gmail.com>
Wed, 7 Jan 2026 20:39:05 +0000 (15:39 -0500)
committergithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Thu, 22 Jan 2026 17:51:22 +0000 (17:51 +0000)
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
res/res_pjsip_pubsub.c

index 6ae0e3ed7b55338f7eb21c2b91a9ff0fa90d4a47..644b54238fdcb13cb81076a215b091d46d178db7 100644 (file)
@@ -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)