Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Michael Niedermayer <michael@niedermayer.cc>
To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Subject: [FFmpeg-devel] [PATCH 2/2] avformat/hls: Be more picky on extensions
Date: Wed, 22 Jan 2025 21:36:09 +0100
Message-ID: <20250122203609.1796499-2-michael@niedermayer.cc> (raw)
In-Reply-To: <20250122203609.1796499-1-michael@niedermayer.cc>

This blocks disallowed extensions from probing
It also requires all available segments to have matching extensions to the format
mpegts is treated independent of the extension

It is recommended to set the whitelists correctly
instead of depending on extensions, but this should help a bit,
and this is easier to backport

Fixes: CVE-2023-6602 II. HLS Force TTY Demuxer
Fixes: CVE-2023-6602 IV. HLS XBIN Demuxer DoS Amplification

The other parts of CVE-2023-6602 have been fixed by prior commits

Found-by: Harvey Phillips of Amazon Element55 (element55)
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
---
 doc/demuxers.texi |  7 +++++++
 libavformat/hls.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index cc81c615dd7..2324b3b4690 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -564,6 +564,13 @@ prefer to use #EXT-X-START if it's in playlist instead of live_start_index.
 @item allowed_extensions
 ',' separated list of file extensions that hls is allowed to access.
 
+@item extension_picky
+This blocks disallowed extensions from probing
+It also requires all available segments to have matching extensions to the format
+except mpegts, which is always allowed.
+It is recommended to set the whitelists correctly instead of depending on extensions
+Enabled by default.
+
 @item max_reload
 Maximum number of times a insufficient list is attempted to be reloaded.
 Default value is 1000.
diff --git a/libavformat/hls.c b/libavformat/hls.c
index 045741c3b4e..93f6d1f1021 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -223,6 +223,7 @@ typedef struct HLSContext {
     AVDictionary *avio_opts;
     AVDictionary *seg_format_opts;
     char *allowed_extensions;
+    int extension_picky;
     int max_reload;
     int http_persistent;
     int http_multiple;
@@ -731,6 +732,40 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url,
     return ret;
 }
 
+static int test_segment(AVFormatContext *s, const AVInputFormat *in_fmt, struct playlist *pls, struct segment *seg)
+{
+    HLSContext *c = s->priv_data;
+    int matchA = 3;
+    int matchF = 0;
+
+    if (!c->extension_picky)
+        return 0;
+
+    if (strcmp(c->allowed_extensions, "ALL"))
+        matchA =      av_match_ext    (seg->url, c->allowed_extensions)
+                 + 2*(ff_match_url_ext(seg->url, c->allowed_extensions) > 0);
+
+    if (!matchA) {
+        av_log(s, AV_LOG_ERROR, "URL %s is not in allowed_extensions\n", seg->url);
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (in_fmt) {
+        if (in_fmt->extensions) {
+            matchF =      av_match_ext(    seg->url, in_fmt->extensions)
+                     + 2*(ff_match_url_ext(seg->url, in_fmt->extensions) > 0);
+        } else if (!strcmp(in_fmt->name, "mpegts"))
+            matchF = 3;
+
+        if (!(matchA & matchF)) {
+            av_log(s, AV_LOG_ERROR, "detected format extension %s mismatches allowed extensions in url %s\n", in_fmt->extensions ? in_fmt->extensions : "none", seg->url);
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    return 0;
+}
+
 static int parse_playlist(HLSContext *c, const char *url,
                           struct playlist *pls, AVIOContext *in)
 {
@@ -989,6 +1024,14 @@ static int parse_playlist(HLSContext *c, const char *url,
                     goto fail;
                 }
 
+                ret = test_segment(c->ctx, pls->ctx ? pls->ctx->iformat : NULL, pls, seg);
+                if (ret < 0) {
+                    av_free(seg->url);
+                    av_free(seg->key);
+                    av_free(seg);
+                    goto fail;
+                }
+
                 if (duration < 0.001 * AV_TIME_BASE) {
                     av_log(c->ctx, AV_LOG_WARNING, "Cannot get correct #EXTINF value of segment %s,"
                                     " set to default value to 1ms.\n", seg->url);
@@ -2114,6 +2157,11 @@ static int hls_read_header(AVFormatContext *s)
             pls->ctx->interrupt_callback = s->interrupt_callback;
             url = av_strdup(pls->segments[0]->url);
             ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, url, NULL, 0, 0);
+
+            for (int n = 0; n < pls->n_segments; n++)
+                if (ret >= 0)
+                    ret = test_segment(s, in_fmt, pls, pls->segments[n]);
+
             if (ret < 0) {
                 /* Free the ctx - it isn't initialized properly at this point,
                 * so avformat_close_input shouldn't be called. If
@@ -2576,6 +2624,8 @@ static const AVOption hls_options[] = {
         OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
         {.str = "3gp,aac,avi,ac3,eac3,flac,mkv,m3u8,m4a,m4s,m4v,mpg,mov,mp2,mp3,mp4,mpeg,mpegts,ogg,ogv,oga,ts,vob,wav"},
         INT_MIN, INT_MAX, FLAGS},
+    {"extension_picky", "Be picky with all extensions matching",
+        OFFSET(extension_picky), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS},
     {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded",
         OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 3}, 0, INT_MAX, FLAGS},
     {"m3u8_hold_counters", "The maximum number of times to load m3u8 when it refreshes without new segments",
-- 
2.48.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  reply	other threads:[~2025-01-22 20:36 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-22 20:36 [FFmpeg-devel] [PATCH 1/2] Revert "avformat/mpegts: Add standard extension so hls can check in extension_picky mode" Michael Niedermayer
2025-01-22 20:36 ` Michael Niedermayer [this message]
2025-01-22 22:47   ` [FFmpeg-devel] [PATCH 2/2] avformat/hls: Be more picky on extensions Kieran Kunhya via ffmpeg-devel
2025-01-23  0:11     ` Michael Niedermayer
2025-01-23 21:54       ` Kieran Kunhya via ffmpeg-devel
2025-01-23 22:35         ` Michael Niedermayer
2025-01-23 21:27   ` Michael Niedermayer
2025-01-25 20:38     ` Michael Niedermayer
2025-01-28  5:11       ` Vittorio Giovara
2025-01-28 12:14         ` Michael Niedermayer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250122203609.1796499-2-michael@niedermayer.cc \
    --to=michael@niedermayer.cc \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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