Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PR] avformat/rtsp: fix silent input truncation in get_word_until_chars (PR #21390)
@ 2026-01-06 12:29 rcx86 via ffmpeg-devel
  0 siblings, 0 replies; only message in thread
From: rcx86 via ffmpeg-devel @ 2026-01-06 12:29 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: rcx86

PR #21390 opened by rcx86
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21390
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21390.patch

The get_word_until_chars function silently truncated input text that exceeded the buffer size, discarding the overflow while advancing the input pointer. This allowed malicious requests (e.g., in SDP parsing) to bypass validation by appending garbage characters to otherwise valid numeric tokens (like ports or payload types), leading to
firewall evasion or protocol smuggling.

Modify get_word_until_chars to return a truncation error. Update callers to propagate this error. Introduce a strict integer parsing helper to reject values with trailing garbage. Update SDP parsing code to validate port and payload type fields strictly.


>From 3e8db2f023213aaf37919574186c9ede5fd0eff0 Mon Sep 17 00:00:00 2001
From: HACKE-RC <60568652+HACKE-RC@users.noreply.github.com>
Date: Sun, 4 Jan 2026 16:35:43 +0530
Subject: [PATCH] avformat/rtsp: fix silent input truncation in
 get_word_until_chars

The get_word_until_chars function silently truncated input text that
exceeded the buffer size, discarding the overflow while advancing the
input pointer. This allowed malicious requests (e.g., in SDP parsing)
to bypass validation by appending garbage characters to otherwise
valid numeric tokens (like ports or payload types), leading to
firewall evasion or protocol smuggling.

Modify get_word_until_chars to return a truncation error. Update
callers to propagate this error. Introduce a strict integer parsing
helper to reject values with trailing garbage. Update SDP parsing
code to validate port and payload type fields strictly.
---
 libavformat/rtsp.c | 76 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 63 insertions(+), 13 deletions(-)

diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index e8f44e571a..c6c4c52cab 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -166,35 +166,74 @@ static int copy_tls_opts_dict(RTSPState *rt, AVDictionary **dict)
 
 #undef ERR_RET
 
-static void get_word_until_chars(char *buf, int buf_size,
-                                 const char *sep, const char **pp)
+/**
+ * Parse a word from the input string until a separator is found.
+ * @return 0 on success, 1 if truncation occurred
+ */
+static int get_word_until_chars(char *buf, int buf_size,
+                                const char *sep, const char **pp)
 {
     const char *p;
     char *q;
+    int truncated = 0;
 
     p = *pp;
     p += strspn(p, SPACE_CHARS);
     q = buf;
     while (!strchr(sep, *p) && *p != '\0') {
-        if ((q - buf) < buf_size - 1)
+        if ((q - buf) < buf_size - 1) {
             *q++ = *p;
+        } else {
+            truncated = 1;
+        }
         p++;
     }
     if (buf_size > 0)
         *q = '\0';
     *pp = p;
+    return truncated;
 }
 
-static void get_word_sep(char *buf, int buf_size, const char *sep,
-                         const char **pp)
+static int get_word_sep(char *buf, int buf_size, const char *sep,
+                        const char **pp)
 {
     if (**pp == '/') (*pp)++;
-    get_word_until_chars(buf, buf_size, sep, pp);
+    return get_word_until_chars(buf, buf_size, sep, pp);
 }
 
-static void get_word(char *buf, int buf_size, const char **pp)
+static int get_word(char *buf, int buf_size, const char **pp)
 {
-    get_word_until_chars(buf, buf_size, SPACE_CHARS, pp);
+    return get_word_until_chars(buf, buf_size, SPACE_CHARS, pp);
+}
+
+/**
+ * Parse an integer from a string, rejecting trailing garbage.
+ * Uses strtol with endptr validation, consistent with FFmpeg patterns.
+ * @return 0 on success, -1 on error (empty, trailing garbage, or overflow)
+ */
+static int parse_strict_int(const char *str, int *result)
+{
+    char *endptr;
+    long val;
+
+    if (!str || !*str)
+        return -1;
+
+    val = strtol(str, &endptr, 10);
+
+    /* Skip trailing whitespace */
+    endptr += strspn(endptr, SPACE_CHARS);
+
+    /* Reject if trailing non-whitespace garbage */
+    if (*endptr != '\0')
+        return -1;
+
+    /* Check range (platform-independent) */
+    if (val < INT_MIN || val > INT_MAX)
+        return -1;
+
+    *result = (int)val;
+    return 0;
 }
 
 /** Parse a string p in the form of Range:npt=xx-xx, and determine the start
@@ -452,7 +491,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
     char buf1[64], st_type[64];
     const char *p;
     enum AVMediaType codec_type;
-    int payload_type;
+    int payload_type, payload;
     AVStream *st;
     RTSPStream *rtsp_st;
     RTSPSource *rtsp_src;
@@ -540,8 +579,13 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
                                   &rtsp_st->exclude_source_addrs,
                                   &rtsp_st->nb_exclude_source_addrs);
 
-        get_word(buf1, sizeof(buf1), &p); /* port */
-        rtsp_st->sdp_port = atoi(buf1);
+        if (get_word(buf1, sizeof(buf1), &p) ||
+            parse_strict_int(buf1, &rtsp_st->sdp_port) < 0 ||
+            rtsp_st->sdp_port < 0 || rtsp_st->sdp_port > 65535) {
+            av_log(s, AV_LOG_WARNING, "Invalid port in SDP m= line: %s\n", buf1);
+            s1->skip_media = 1;
+            return;
+        }
 
         get_word(buf1, sizeof(buf1), &p); /* protocol */
         if (!strcmp(buf1, "udp"))
@@ -550,8 +594,14 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1,
             rtsp_st->feedback = 1;
 
         /* XXX: handle list of formats */
-        get_word(buf1, sizeof(buf1), &p); /* format list */
-        rtsp_st->sdp_payload_type = atoi(buf1);
+        if (get_word(buf1, sizeof(buf1), &p) ||
+            parse_strict_int(buf1, &payload) < 0 ||
+            payload < 0 || payload > 127) {
+            av_log(s, AV_LOG_WARNING, "Invalid payload type in SDP: %s\n", buf1);
+            s1->skip_media = 1;
+            return;
+        }
+        rtsp_st->sdp_payload_type = payload;
 
         if (!strcmp(ff_rtp_enc_name(rtsp_st->sdp_payload_type), "MP2T")) {
             /* no corresponding stream */
-- 
2.49.1

_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-01-06 12:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-06 12:29 [FFmpeg-devel] [PR] avformat/rtsp: fix silent input truncation in get_word_until_chars (PR #21390) rcx86 via ffmpeg-devel

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git