channelstorage_cpp_map_name_id: Add read locking around retrievals.

When we retrieve a channel from a C++ map, we actually get back a wrapper
object that points to the channel then right after we retrieve it, we bump its
reference count.  There's a tiny chance however that between those two
statements a delete and/or unref might happen which would cause the wrapper
object or the channel itself to become invalid resulting in a SEGV.  To avoid
this we now perform a read lock on the driver around those statements.

Resolves: #1491
This commit is contained in:
George Joseph
2025-10-01 08:30:52 -06:00
parent bce37d3b2f
commit bbb9f5ead5

View File

@@ -141,7 +141,17 @@ static int delete_channel(struct ast_channelstorage_instance *driver,
/*! \brief returns number of active/allocated channels */ /*! \brief returns number of active/allocated channels */
static int active_channels(struct ast_channelstorage_instance *driver) static int active_channels(struct ast_channelstorage_instance *driver)
{ {
return driver ? getdb(driver).size() : 0; int count = 0;
if (!driver) {
return 0;
}
rdlock(driver);
count = getdb(driver).size();
unlock(driver);
return count;
} }
static struct ast_channel *callback(struct ast_channelstorage_instance *driver, static struct ast_channel *callback(struct ast_channelstorage_instance *driver,
@@ -454,14 +464,17 @@ static struct ast_channel *get_by_uniqueid(struct ast_channelstorage_instance *d
{ {
struct ast_channel *chan = NULL; struct ast_channel *chan = NULL;
char *search = uniqueid ? ast_str_to_lower(ast_strdupa(uniqueid)) : NULL; char *search = uniqueid ? ast_str_to_lower(ast_strdupa(uniqueid)) : NULL;
if (ast_strlen_zero(uniqueid)) { if (ast_strlen_zero(uniqueid)) {
return NULL; return NULL;
} }
rdlock(driver);
auto rtn = map_by_id(driver).find(search); auto rtn = map_by_id(driver).find(search);
if (rtn != map_by_id(driver).end()) { if (rtn != map_by_id(driver).end()) {
chan = ao2_bump((struct ast_channel *)rtn->second); chan = ao2_bump((struct ast_channel *)rtn->second);
} }
unlock(driver);
return chan; return chan;
} }
@@ -469,16 +482,21 @@ static struct ast_channel *get_by_uniqueid(struct ast_channelstorage_instance *d
static struct ast_channel *get_by_name_exact(struct ast_channelstorage_instance *driver, static struct ast_channel *get_by_name_exact(struct ast_channelstorage_instance *driver,
const char *name) const char *name)
{ {
struct ast_channel *chan = NULL;
char *search = name ? ast_str_to_lower(ast_strdupa(name)) : NULL; char *search = name ? ast_str_to_lower(ast_strdupa(name)) : NULL;
if (ast_strlen_zero(name)) { if (ast_strlen_zero(name)) {
return NULL; return NULL;
} }
auto chan = getdb(driver).find(search);
if (chan != getdb(driver).end()) {
return ao2_bump((struct ast_channel *)chan->second);
}
return NULL; rdlock(driver);
auto rtn = getdb(driver).find(search);
if (rtn != getdb(driver).end()) {
chan = ao2_bump((struct ast_channel *)rtn->second);
}
unlock(driver);
return chan;
} }
static struct ast_channel *get_by_name_prefix(struct ast_channelstorage_instance *driver, static struct ast_channel *get_by_name_prefix(struct ast_channelstorage_instance *driver,
@@ -493,10 +511,14 @@ static struct ast_channel *get_by_name_prefix(struct ast_channelstorage_instance
} }
l_name = ast_str_to_lower(ast_strdupa(name)); l_name = ast_str_to_lower(ast_strdupa(name));
rdlock(driver);
auto rtn = getdb(driver).lower_bound(l_name); auto rtn = getdb(driver).lower_bound(l_name);
if (rtn != getdb(driver).end()) { if (rtn != getdb(driver).end()) {
chan = ao2_bump((struct ast_channel *)rtn->second); chan = ao2_bump((struct ast_channel *)rtn->second);
} }
unlock(driver);
return chan; return chan;
} }