History

avformat/hls: Be more picky on extensions

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

Michael Niedermayer committed 1 year ago

Commit 91d96dc1 parent c733e2b2 files · +57 −0Browse files

Unified · Split

2 files
  1. doc/demuxers.texi +7 −0
  2. libavformat/hls.c +50 −0
doc/demuxers.texi+7−0
@@ -564,6 +564,13 @@ prefer to use #EXT-X-START if it's in playlist instead of live_start_index. · 563 unmodified lines
564564 @item allowed_extensions
565565 ',' separated list of file extensions that hls is allowed to access.
566566
567+@item extension_picky
568+This blocks disallowed extensions from probing
569+It also requires all available segments to have matching extensions to the format
570+except mpegts, which is always allowed.
571+It is recommended to set the whitelists correctly instead of depending on extensions
572+Enabled by default.
573+
567574 @item max_reload
568575 Maximum number of times a insufficient list is attempted to be reloaded.
569576 Default value is 1000.
libavformat/hls.c+50−0
@@ -223,6 +223,7 @@ typedef struct HLSContext { · 222 unmodified lines
223223 AVDictionary *avio_opts;
224224 AVDictionary *seg_format_opts;
225225 char *allowed_extensions;
226+ int extension_picky;
226227 int max_reload;
227228 int http_persistent;
228229 int http_multiple;
@@ -731,6 +732,40 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, · 502 unmodified lines
731732 return ret;
732733 }
733734
735+static int test_segment(AVFormatContext *s, const AVInputFormat *in_fmt, struct playlist *pls, struct segment *seg)
736+{
737+ HLSContext *c = s->priv_data;
738+ int matchA = 3;
739+ int matchF = 0;
740+
741+ if (!c->extension_picky)
742+ return 0;
743+
744+ if (strcmp(c->allowed_extensions, "ALL"))
745+ matchA = av_match_ext (seg->url, c->allowed_extensions)
746+ + 2*(ff_match_url_ext(seg->url, c->allowed_extensions) > 0);
747+
748+ if (!matchA) {
749+ av_log(s, AV_LOG_ERROR, "URL %s is not in allowed_extensions\n", seg->url);
750+ return AVERROR_INVALIDDATA;
751+ }
752+
753+ if (in_fmt) {
754+ if (in_fmt->extensions) {
755+ matchF = av_match_ext( seg->url, in_fmt->extensions)
756+ + 2*(ff_match_url_ext(seg->url, in_fmt->extensions) > 0);
757+ } else if (!strcmp(in_fmt->name, "mpegts"))
758+ matchF = 3;
759+
760+ if (!(matchA & matchF)) {
761+ 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);
762+ return AVERROR_INVALIDDATA;
763+ }
764+ }
765+
766+ return 0;
767+}
768+
734769 static int parse_playlist(HLSContext *c, const char *url,
735770 struct playlist *pls, AVIOContext *in)
736771 {
@@ -989,6 +1024,14 @@ static int parse_playlist(HLSContext *c, const char *url, · 252 unmodified lines
9891024 goto fail;
9901025 }
9911026
1027+ ret = test_segment(c->ctx, pls->ctx ? pls->ctx->iformat : NULL, pls, seg);
1028+ if (ret < 0) {
1029+ av_free(seg->url);
1030+ av_free(seg->key);
1031+ av_free(seg);
1032+ goto fail;
1033+ }
1034+
9921035 if (duration < 0.001 * AV_TIME_BASE) {
9931036 av_log(c->ctx, AV_LOG_WARNING, "Cannot get correct #EXTINF value of segment %s,"
9941037 " set to default value to 1ms.\n", seg->url);
@@ -2114,6 +2157,11 @@ static int hls_read_header(AVFormatContext *s) · 1119 unmodified lines
21142157 pls->ctx->interrupt_callback = s->interrupt_callback;
21152158 url = av_strdup(pls->segments[0]->url);
21162159 ret = av_probe_input_buffer(&pls->pb.pub, &in_fmt, url, NULL, 0, 0);
2160+
2161+ for (int n = 0; n < pls->n_segments; n++)
2162+ if (ret >= 0)
2163+ ret = test_segment(s, in_fmt, pls, pls->segments[n]);
2164+
21172165 if (ret < 0) {
21182166 /* Free the ctx - it isn't initialized properly at this point,
21192167 * so avformat_close_input shouldn't be called. If
@@ -2576,6 +2624,8 @@ static const AVOption hls_options[] = { · 456 unmodified lines
25762624 OFFSET(allowed_extensions), AV_OPT_TYPE_STRING,
25772625 {.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"},
25782626 INT_MIN, INT_MAX, FLAGS},
2627+ {"extension_picky", "Be picky with all extensions matching",
2628+ OFFSET(extension_picky), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS},
25792629 {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded",
25802630 OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 3}, 0, INT_MAX, FLAGS},
25812631 {"m3u8_hold_counters", "The maximum number of times to load m3u8 when it refreshes without new segments",

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t