[Asterisk-code-review] func_lock: Prevent module unloading in-use module. (asterisk[16])

Friendly Automation asteriskteam at digium.com
Fri Jun 11 13:24:52 CDT 2021


Friendly Automation has submitted this change. ( https://gerrit.asterisk.org/c/asterisk/+/16095 )

Change subject: func_lock: Prevent module unloading in-use module.
......................................................................

func_lock: Prevent module unloading in-use module.

The scenario where a channel still has an associated datastore we
cannot unload since there is a function pointer to the destroy and fixup
functions in play.  Thus increase the module ref count whenever we
allocate a datastore, and decrease it during destroy.

In order to tighten the race that still exists in spite of this (below)
add some extra failure cases to prevent allocations in these cases.

Race:

If module ref is zero, an LOCK or TRYLOCK is invoked (near)
simultaneously on a channel that has NOT PREVIOUSLY taken a lock, and if
in such a case the datastore is created *prior* to unloading being set
to true (first step in module unload) then it's possible that the module
will unload with the destructor being called (and segfault) post the
module being unloaded.  The module will however wait for such locks to
release prior to unloading.

If post that we can recheck the module ref before returning the we can
(in theory, I think) eliminate the last of the race.  This race is
mostly theoretical in nature.

Change-Id: I21a514a0b56755c578a687f4867eacb8b59e23cf
Signed-off-by: Jaco Kroon <jaco at uls.co.za>
---
M funcs/func_lock.c
1 file changed, 14 insertions(+), 1 deletion(-)

Approvals:
  George Joseph: Looks good to me, approved
  Friendly Automation: Approved for Submit



diff --git a/funcs/func_lock.c b/funcs/func_lock.c
index f64011f..ccd1150 100644
--- a/funcs/func_lock.c
+++ b/funcs/func_lock.c
@@ -157,6 +157,8 @@
 	AST_LIST_UNLOCK(oldlist);
 	AST_LIST_HEAD_DESTROY(oldlist);
 	ast_free(oldlist);
+
+	ast_module_unref(ast_module_info->self);
 }
 
 static void lock_fixup(void *data, struct ast_channel *oldchan, struct ast_channel *newchan)
@@ -191,7 +193,12 @@
 	struct timeval now;
 
 	if (!lock_store) {
-		ast_debug(1, "Channel %s has no lock datastore, so we're allocating one.\n", ast_channel_name(chan));
+		if (unloading) {
+			ast_log(LOG_ERROR, "%sLOCK has no datastore and func_lock is unloading, failing.\n",
+					trylock ? "TRY" : "");
+			return -1;
+		}
+
 		lock_store = ast_datastore_alloc(&lock_info, NULL);
 		if (!lock_store) {
 			ast_log(LOG_ERROR, "Unable to allocate new datastore.  No locks will be obtained.\n");
@@ -210,6 +217,9 @@
 		lock_store->data = list;
 		AST_LIST_HEAD_INIT(list);
 		ast_channel_datastore_add(chan, lock_store);
+
+		/* We cannot unload until this channel has released the lock_store */
+		ast_module_ref(ast_module_info->self);
 	} else
 		list = lock_store->data;
 
@@ -223,6 +233,9 @@
 
 	if (!current) {
 		if (unloading) {
+			ast_log(LOG_ERROR,
+				"Lock doesn't exist whilst unloading.  %sLOCK will fail.\n",
+				trylock ? "TRY" : "");
 			/* Don't bother */
 			AST_LIST_UNLOCK(&locklist);
 			return -1;

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/16095
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: 16
Gerrit-Change-Id: I21a514a0b56755c578a687f4867eacb8b59e23cf
Gerrit-Change-Number: 16095
Gerrit-PatchSet: 2
Gerrit-Owner: George Joseph <gjoseph at digium.com>
Gerrit-Reviewer: Friendly Automation
Gerrit-Reviewer: George Joseph <gjoseph at digium.com>
Gerrit-CC: Jaco Kroon <jaco at uls.co.za>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20210611/0b91ff58/attachment-0001.html>


More information about the asterisk-code-review mailing list