Commit fc0db829b8 for freeswitch.com

commit fc0db829b87d1a5a3043e355b4294c41851b13c6
Author: Dmitry Verenitsin <morbit85@gmail.com>
Date:   Sat Aug 8 21:55:22 2026 +0500

    Merge commit from fork

    `rtmp_handle_control()` formats the control-message body into a fixed
    200-byte stack buffer with an unbounded `sprintf` loop whose iteration
    count is the wire message length. A body of ~70 bytes or more runs the
    write off the end of `buf`, corrupting the stack frame; the length is
    taken straight from the chunk header and reaches this path before any
    login, so a remote peer can trigger it.

    Bound the loop with `snprintf` against the remaining space and stop when
    the buffer is full. This also caps the iteration count, so the loop can
    no longer read `state->buf` past what was reassembled. The hex dump is
    debug-only output, so capping it changes nothing operational.

diff --git a/src/mod/endpoints/mod_rtmp/rtmp.c b/src/mod/endpoints/mod_rtmp/rtmp.c
index 285bc81103..74097f13b3 100644
--- a/src/mod/endpoints/mod_rtmp/rtmp.c
+++ b/src/mod/endpoints/mod_rtmp/rtmp.c
@@ -81,11 +81,18 @@ void rtmp_handle_control(rtmp_session_t *rsession, int amfnumber)
 	rtmp_state_t *state = &rsession->amfstate[amfnumber];
 	char buf[200] = { 0 };
 	char *p = buf;
+	char *end = buf + sizeof(buf);
 	int type = state->buf[0] << 8 | state->buf[1];
 	int i;

-	for (i = 2; i < state->origlen; i++) {
-		p += sprintf(p, "%02x ", state->buf[i] & 0xFF);
+	for (i = 2; i < state->origlen && p < end; i++) {
+		int n = snprintf(p, end - p, "%02x ", state->buf[i] & 0xFF);
+
+		if (n <= 0 || n >= end - p) {
+			break;
+		}
+
+		p += n;
 	}

 	switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG, "Control (%d): %s\n", type, buf);