java-topology/defects/freeswitch/patch/0001-conference-relationship-precompute-matrix.patch

104 lines
4.4 KiB
Diff

# UNDF: UNDF-2026-000000073
diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c
index 1234567..abcdef0 100644
--- a/src/mod/applications/mod_conference/mod_conference.c
+++ b/src/mod/applications/mod_conference/mod_conference.c
@@ -612,6 +612,58 @@ static void conference_loop_output(conference_obj_t *conference)
/* Create write frame once per member who is not deaf for each sample in the main frame */
for (omember = conference->members; omember; omember = omember->next) {
switch_size_t ok = 1;
+
+/*
+ * CWE-407 fix: Pre-compute relationship exclusion matrix outside the per-sample loop.
+ *
+ * Original code scanned imember->relationships (linked list, O(R)) and omember->relationships (O(R))
+ * for EVERY sample of EVERY (omember, imember) pair — O(S * M * M * R) per mix cycle.
+ *
+ * Fix: before the per-sample loop for this omember, build a bitmask of imembers whose audio
+ * should be excluded for this omember. One O(M*R) pass replaces O(S*M*R) per omember.
+ *
+ * Implementation uses switch_core stack allocation (conference->member_count bounded).
+ * relationship_total guard is preserved — skip if no relationships exist.
+ */
+
+ /* --- BEGIN relationship pre-computation --- */
+ /* exclude_audio[imember->id % MAX_MEMBERS] set → omember should not hear imember */
+#define CONF_MAX_MEMBERS 512
+ uint8_t exclude_audio[CONF_MAX_MEMBERS];
+ memset(exclude_audio, 0, sizeof(exclude_audio));
+
+ if (conference->relationship_total) {
+ conference_member_t *im2;
+ for (im2 = conference->members; im2; im2 = im2->next) {
+ if (im2 == omember) continue;
+ if (!conference_utils_member_test_flag(im2, MFLAG_HAS_AUDIO)) continue;
+
+ conference_relationship_t *rel;
+ switch_size_t found = 0;
+ /* Check im2 → omember: can im2 speak to omember? */
+ for (rel = im2->relationships; rel; rel = rel->next) {
+ if ((rel->id == omember->id || rel->id == 0) && !switch_test_flag(rel, RFLAG_CAN_SPEAK)) {
+ exclude_audio[im2->id % CONF_MAX_MEMBERS] = 1;
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ /* Check omember → im2: can omember hear im2? */
+ for (rel = omember->relationships; rel; rel = rel->next) {
+ if ((rel->id == im2->id || rel->id == 0) && !switch_test_flag(rel, RFLAG_CAN_HEAR)) {
+ exclude_audio[im2->id % CONF_MAX_MEMBERS] = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ /* --- END relationship pre-computation --- */
if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING) ||
(!conference_utils_member_test_flag(omember, MFLAG_NOCHANNEL) && !switch_channel_test_flag(omember->channel, CF_AUDIO))) {
@@ -641,24 +693,15 @@ static void conference_loop_output(conference_obj_t *conference)
z -= (int32_t) bptr[x];
}
- /* when there are relationships, we have to do more work by scouring all the members to see if there are any
- reasons why we should not be hearing a particular member, and if not, delete their samples as well.
- */
- if (conference->relationship_total) {
- for (imember = conference->members; imember; imember = imember->next) {
- if (imember != omember && conference_utils_member_test_flag(imember, MFLAG_HAS_AUDIO)) {
- conference_relationship_t *rel;
- switch_size_t found = 0;
- int16_t *rptr = (int16_t *) imember->frame;
- for (rel = imember->relationships; rel; rel = rel->next) {
- if ((rel->id == omember->id || rel->id == 0) && !switch_test_flag(rel, RFLAG_CAN_SPEAK)) {
- z -= (int32_t) rptr[x];
- found = 1;
- break;
- }
- }
- if (!found) {
- for (rel = omember->relationships; rel; rel = rel->next) {
- if ((rel->id == imember->id || rel->id == 0) && !switch_test_flag(rel, RFLAG_CAN_HEAR)) {
- z -= (int32_t) rptr[x];
- break;
- }
- }
- }
- }
- }
- }
+ /* CWE-407 fix: use pre-computed exclude matrix — O(1) lookup per (omember, imember) per sample */
+ if (conference->relationship_total) {
+ for (imember = conference->members; imember; imember = imember->next) {
+ if (imember != omember && conference_utils_member_test_flag(imember, MFLAG_HAS_AUDIO)) {
+ if (exclude_audio[imember->id % CONF_MAX_MEMBERS]) {
+ int16_t *rptr = (int16_t *) imember->frame;
+ z -= (int32_t) rptr[x];
+ }
+ }
+ }
+ }
/* Now we can convert to 16 bit. */