]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
stasis/app: don't lock an app before a call to send
authorKevin Harwell <kharwell@digium.com>
Mon, 27 Jan 2020 18:01:15 +0000 (12:01 -0600)
committerKevin Harwell <kharwell@digium.com>
Mon, 27 Jan 2020 18:11:12 +0000 (12:11 -0600)
Calling 'app_send' eventually calls the app's message handler. It's possible
for a handler to obtain a lock on another object, and then need/want to lock
the app object. If the caller of 'app_send' locks the app object prior to
calling then there's a potential for a deadlock, if another thread calls
'app_send' without locking.

This patch makes it so 'app_send' is not called with the app object locked in
the section of code doing such.

ASTERISK-28423 #close

Change-Id: I6767c6d0933c7db1b984018966eefca4c0638a27

res/stasis/app.c

index c1b7fae3a0b4dfc37f58d1abf79c0481da0e55a2..afea2c6cc462801f13de36d87aa8f95963c3ece2 100644 (file)
@@ -1169,8 +1169,23 @@ void app_update(struct stasis_app *app, stasis_app_cb handler, void *data)
                        "timestamp", ast_json_timeval(ast_tvnow(), NULL),
                        "application", app->name);
                if (msg) {
+                       /*
+                        * The app must be unlocked before calling 'send' since a handler may
+                        * subsequently attempt to grab the app lock after first obtaining a
+                        * lock for another object, thus causing a deadlock.
+                        */
+                       ao2_unlock(app);
                        app_send(app, msg);
+                       ao2_lock(app);
                        ast_json_unref(msg);
+                       if (!app->handler) {
+                               /*
+                                * If the handler disappeared then the app was deactivated. In that
+                                * case don't replace. Re-activation will reset the handler later.
+                                */
+                               ao2_unlock(app);
+                               return;
+                       }
                }
        } else {
                ast_verb(1, "Activating Stasis app '%s'\n", app->name);