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

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.


>From 6f53e62340154566ad922b30b13b1c7c0f68425a Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Thu, 21 May 2026 21:59:01 +0200
Subject: [PATCH] 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.
---
 libavformat/dashdec.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c
index cac2250634..bed82fcf45 100644
--- a/libavformat/dashdec.c
+++ b/libavformat/dashdec.c
@@ -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}
 };
 
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to