func_lock: Fix memory corruption during unload.

AST_TRAVERSE accessess current as current = current->(field).next ...
and since we free current (and ast_free poisons the memory) we either
end up on a ast_mutex_lock to a non-existing lock that can never be
obtained, or a segfault.

Incidentally add logging in the "we have to wait for a lock to release"
case, and remove an ineffective statement that sets memory that was just
cleared by ast_calloc to zero.

Change-Id: Id19ba3d9867b23d0e6783b97e6ecd8e62698b8c3
Signed-off-by: Jaco Kroon <jaco@uls.co.za>
This commit is contained in:
Jaco Kroon 2021-05-22 14:42:04 +02:00 committed by George Joseph
parent 6bd741b77d
commit a3df5d7de8
1 changed files with 8 additions and 2 deletions

View File

@ -249,7 +249,6 @@ static int get_lock(struct ast_channel *chan, char *lockname, int trylock)
AST_LIST_UNLOCK(&locklist);
return -1;
}
current->requesters = 0;
AST_LIST_INSERT_TAIL(&locklist, current, entries);
}
/* Add to requester list */
@ -449,9 +448,16 @@ static int unload_module(void)
ast_custom_function_unregister(&trylock_function);
AST_LIST_LOCK(&locklist);
AST_LIST_TRAVERSE(&locklist, current, entries) {
while ((current = AST_LIST_REMOVE_HEAD(&locklist, entries))) {
int warned = 0;
ast_mutex_lock(&current->mutex);
while (current->owner || current->requesters) {
if (!warned) {
ast_log(LOG_WARNING, "Waiting for %d requesters for %s lock %s.\n",
current->requesters, current->owner ? "locked" : "unlocked",
current->name);
warned = 1;
}
/* either the mutex is locked, or other parties are currently in get_lock,
* we need to wait for all of those to clear first */
ast_cond_wait(&current->cond, &current->mutex);