2 KiB
asterisk-0002 — app_confbridge: active_list/waiting_list have no channel-name index
Severity: MEDIUM
CWE: CWE-407 (Inefficient Algorithmic Complexity)
Target: asterisk/asterisk
File: apps/app_confbridge.c, apps/confbridge/include/confbridge.h
Lines: confbridge.h:260-261, app_confbridge.c:1757, 1768, 3387, 3468, 3687
Description
confbridge_conference stores participants as two plain linked lists:
/* confbridge.h:260-261 */
AST_LIST_HEAD_NOLOCK(, confbridge_user) active_list;
AST_LIST_HEAD_NOLOCK(, confbridge_user) waiting_list;
Every operation that identifies a user by channel name (kick, mute, unmute, video-source selection, AMI/ARI events) traverses the entire list:
/* app_confbridge.c:1757-1776 */
AST_LIST_TRAVERSE(&conference->active_list, user, list) {
if (strcasecmp(ast_channel_name(user->chan),
old_snapshot->base->name) == 0) {
found_user = 1;
break;
}
}
if (!found_user && conference->waitingusers) {
AST_LIST_TRAVERSE(&conference->waiting_list, user, list) {
if (strcasecmp(ast_channel_name(user->chan), ...) == 0) { ... }
}
}
There are at least 12 traversal sites in app_confbridge.c. In a
conference with P participants each AMI/ARI kick/mute costs O(P). A
conference of 500 participants (common for webinar/town-hall use cases) with
frequent moderator actions creates quadratic work per conference.
Complexity
- Before: O(P) per user-by-name lookup across P participants
- After: O(1) with an
ao2_containerkeyed on channel name
Fix
Add an ao2_container *users_by_name field to confbridge_conference,
keyed on ast_channel_name(user->chan). Link/unlink on join/leave.
Replace all AST_LIST_TRAVERSE + strcasecmp patterns with a single
ao2_find(conference->users_by_name, channel_name, OBJ_SEARCH_KEY).
Patch
defects/asterisk/patch/asterisk-0002.patch
Test
defects/asterisk/unit/AsteriskTest.java — benchmark ASTERISK_CONFBRIDGE_USER_FIND