Commit 30cdb387ae for freeswitch.com
commit 30cdb387ae0fac0cbbeb6ac05416aaffb9252258
Author: Dmitry Verenitsin <morbit85@gmail.com>
Date: Sat Aug 8 20:18:50 2026 +0500
Merge commit from fork
The positive-offset branch of `${variable:offset}` expansion advanced
`sub_val` past the cloned heap buffer without bounds-checking `offset`
against `strlen(sub_val)`. Subsequent `strlen()` and `strcat()` then
read adjacent heap memory into the output buffer.
diff --git a/src/switch_event.c b/src/switch_event.c
index 25bf961512..9d8907d09a 100644
--- a/src/switch_event.c
+++ b/src/switch_event.c
@@ -2456,7 +2456,11 @@ SWITCH_DECLARE(char *) switch_event_expand_headers_check(switch_event_t *event,
}
if (offset >= 0) {
- sub_val += offset;
+ if ((size_t) offset > strlen(sub_val)) {
+ *cloned_sub_val = '\0';
+ } else {
+ sub_val += offset;
+ }
} else if ((size_t) abs(offset) <= strlen(sub_val)) {
sub_val = cloned_sub_val + (strlen(cloned_sub_val) + offset);
}
diff --git a/tests/unit/switch_event.c b/tests/unit/switch_event.c
index bf8c3f43d2..4ee17d5eb8 100644
--- a/tests/unit/switch_event.c
+++ b/tests/unit/switch_event.c
@@ -104,6 +104,63 @@ FST_TEST_BEGIN(benchmark)
}
FST_TEST_END()
+FST_TEST_BEGIN(expand_headers_offset)
+{
+ /* Covers the ${var:offset[:length]} slicing branches in
+ * switch_event_expand_headers_check(). */
+ static const struct {
+ const char *expr;
+ const char *expected;
+ const char *note;
+ } cases[] = {
+ /* offset == 0: no clone (outer offset||ooffset guard is false). */
+ { "${foo:0}", "ABC", "offset=0 identity, no clone" },
+ { "${empty:0}", "", "offset=0 on empty value" },
+ /* ooffset alone forces the clone, front offset is a no-op. */
+ { "${foo:0:2}", "AB", "offset=0 with ooffset" },
+ /* Positive offset within range. */
+ { "${foo:1}", "BC", "positive in-range" },
+ { "${foo:3}", "", "offset == strlen boundary" },
+ { "${foo:99}", "", "offset > strlen yields empty" },
+ { "${empty:5}", "", "offset > strlen on empty value" },
+ /* Combined offset:length form. */
+ { "${foo:1:1}", "B", "offset:length in range" },
+ { "${foo:0:3}", "ABC", "ooffset == strlen, strict < gate skips trim" },
+ { "${foo:99:2}", "", "offset > strlen with ooffset, gate no-ops" },
+ /* Negative offsets. */
+ { "${foo:-1}", "C", "negative offset in range" },
+ { "${foo:-3}", "ABC", "abs(offset) == strlen, <= gate boundary" },
+ { "${foo:-99}", "ABC", "abs(offset) > strlen, gate falls through" },
+ };
+ switch_event_t *event = NULL;
+ switch_status_t status;
+ size_t i;
+
+ status = switch_event_create(&event, SWITCH_EVENT_MESSAGE);
+ fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Failed to create event");
+
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "foo", "ABC");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "empty", "");
+
+ for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ char msg[160];
+ char *out = switch_event_expand_headers(event, cases[i].expr);
+
+ switch_snprintf(msg, sizeof(msg), "%s: %s -> expected '%s', got '%s'",
+ cases[i].note, cases[i].expr, cases[i].expected,
+ out ? out : "(null)");
+
+ fst_xcheck(out && !strcmp(out, cases[i].expected), msg);
+
+ if (out != cases[i].expr) {
+ switch_safe_free(out);
+ }
+ }
+
+ switch_event_destroy(&event);
+}
+FST_TEST_END()
+
FST_SUITE_END()
FST_MINCORE_END()