You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-06-19 19:03:00 +02:00
avformat/dashdec: bound manifest reloads and fragment-open retries
Mirror the HLS demuxer's max_reload pattern Reported as a DoS finding by Xueqing. Verified with the supplied PoC server: a 30s ffmpeg run that previously generated ~10000 requests without termination now exits in ~100ms after exactly max_reload fragment-open failures.
This commit is contained in:
committed by
michaelni
parent
461fb22053
commit
4945e33e98
@@ -113,6 +113,7 @@ struct representation {
|
||||
int64_t cur_seg_offset;
|
||||
int64_t cur_seg_size;
|
||||
struct fragment *cur_seg;
|
||||
int n_open_failures; /* consecutive open_input failures since last good read */
|
||||
|
||||
/* Currently active Media Initialization Section */
|
||||
struct fragment *init_section;
|
||||
@@ -157,6 +158,7 @@ typedef struct DASHContext {
|
||||
char *allowed_extensions;
|
||||
AVDictionary *avio_opts;
|
||||
int max_url_size;
|
||||
int max_reload;
|
||||
char *cenc_decryption_key;
|
||||
char *cenc_decryption_keys;
|
||||
|
||||
@@ -1649,6 +1651,7 @@ static struct fragment *get_current_fragment(struct representation *pls)
|
||||
struct fragment *seg = NULL;
|
||||
struct fragment *seg_ptr = NULL;
|
||||
DASHContext *c = pls->parent->priv_data;
|
||||
int reload_count = 0;
|
||||
|
||||
while (( !ff_check_interrupt(c->interrupt_callback)&& pls->n_fragments > 0)) {
|
||||
if (pls->cur_seq_no < pls->n_fragments) {
|
||||
@@ -1666,6 +1669,12 @@ static struct fragment *get_current_fragment(struct representation *pls)
|
||||
seg->url_offset = seg_ptr->url_offset;
|
||||
return seg;
|
||||
} else if (c->is_live) {
|
||||
if (reload_count++ >= c->max_reload) {
|
||||
av_log(pls->parent, AV_LOG_ERROR,
|
||||
"Reached max manifest reloads (%d) at seq %"PRId64"\n",
|
||||
c->max_reload, pls->cur_seq_no);
|
||||
return NULL;
|
||||
}
|
||||
refresh_manifest(pls->parent);
|
||||
} else {
|
||||
break;
|
||||
@@ -1856,9 +1865,17 @@ restart:
|
||||
goto end;
|
||||
}
|
||||
av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist\n");
|
||||
if (++v->n_open_failures > c->max_reload) {
|
||||
av_log(v->parent, AV_LOG_ERROR,
|
||||
"Reached max consecutive fragment open failures (%d), giving up\n",
|
||||
c->max_reload);
|
||||
ret = AVERROR_EOF;
|
||||
goto end;
|
||||
}
|
||||
v->cur_seq_no++;
|
||||
goto restart;
|
||||
}
|
||||
v->n_open_failures = 0;
|
||||
}
|
||||
|
||||
if (v->init_sec_buf_read_offset < v->init_sec_data_len) {
|
||||
@@ -2505,6 +2522,8 @@ static const AVOption dash_options[] = {
|
||||
INT_MIN, INT_MAX, FLAGS},
|
||||
{ "cenc_decryption_key", "Media default decryption key (hex)", OFFSET(cenc_decryption_key), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
|
||||
{ "cenc_decryption_keys", "Media decryption keys by KID (hex)", OFFSET(cenc_decryption_keys), AV_OPT_TYPE_STRING, {.str = NULL}, INT_MIN, INT_MAX, .flags = FLAGS },
|
||||
{ "max_reload", "Maximum number of manifest reloads in get_current_fragment() before giving up",
|
||||
OFFSET(max_reload), AV_OPT_TYPE_INT, { .i64 = 100 }, 0, INT_MAX, FLAGS },
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user