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 <[email protected]>
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 -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to