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

## Security Fixes for HLS Module

### 1. `avformat/hlsenc: Fix heap buffer overflow in parse_playlist()`
- **Issue**: When parsing `IV=0x...` and `URI="..."` tokens, `av_strlcpy()` 
used `end - ptr` as the destination size instead of the actual buffer size. A 
crafted playlist with IV/URI tokens longer than 33 bytes could overflow into 
adjacent heap data.
- **Fix**: Use `FFMIN(end - ptr + 1, sizeof(buf))` to cap the copy size to the 
actual destination buffer.

### 2. `avformat/hls: Enforce protocol checks when opening child playlists`
- **Issue**: When parsing a master playlist, the demuxer called 
`c->ctx->io_open()` directly for child playlists, bypassing the `open_url()` 
helper that enforces protocol whitelisting (file/http/data) and file extension 
checks.
- **Fix**: Route the `!in` branch through `open_url()` so all child playlists 
are subject to the same security policy as segment URLs.

### 3. `avformat/hlsenc: Handle extensionless URIs in extract_segment_number()`
- **Issue**: `extract_segment_number()` called `strrchr(filename, '.')` and 
immediately did `dot - 1` without NULL check. A segment URI without an 
extension caused undefined behavior (NULL pointer arithmetic).
- **Fix**: Add NULL check and return -1 early when no dot is found.


>From d3fc087d5d5d6d9d2be566f94cb99d0754ae9598 Mon Sep 17 00:00:00 2001
From: Steven Liu <[email protected]>
Date: Thu, 9 Jul 2026 13:01:31 +0800
Subject: [PATCH 1/3] avformat/hlsenc: Fix heap buffer overflow in
 parse_playlist()

Fix: vulnerability:019f3b84-903b-75fb-a8de-fe6f84d6bc32

When parsing IV=0x... followed by a comma, end - ptr was passed directly
to av_strlcpy() as the destination size. Since iv_string is only 33 bytes
(KEYSIZE*2 + 1), a long IV token could overflow into adjacent heap data.

Use FFMIN(end - ptr + 1, sizeof(buf)) to cap the copy size to the actual
buffer size. Apply the same fix to key_uri parsing for consistency.

Fixes a heap buffer overflow in append_list mode when reading an existing
playlist with a crafted IV or URI token length.

Founded-by: depthfirst
Signed-off-by: Steven Liu <[email protected]>
---
 libavformat/hlsenc.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 0b69ae4b3b..3a8499e3b8 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -30,6 +30,7 @@
 
 #include "libavutil/attributes_internal.h"
 #include "libavutil/avassert.h"
+#include "libavutil/macros.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/avstring.h"
 #include "libavutil/bprint.h"
@@ -1202,7 +1203,7 @@ static int parse_playlist(AVFormatContext *s, const char 
*url, VariantStream *vs
                 ptr += strlen("URI=\"");
                 end = av_stristr(ptr, ",");
                 if (end) {
-                    av_strlcpy(vs->key_uri, ptr, end - ptr);
+                    av_strlcpy(vs->key_uri, ptr, FFMIN(end - ptr + 1, 
sizeof(vs->key_uri)));
                 } else {
                     av_strlcpy(vs->key_uri, ptr, sizeof(vs->key_uri));
                 }
@@ -1213,7 +1214,7 @@ static int parse_playlist(AVFormatContext *s, const char 
*url, VariantStream *vs
                 ptr += strlen("IV=0x");
                 end = av_stristr(ptr, ",");
                 if (end) {
-                    av_strlcpy(vs->iv_string, ptr, end - ptr);
+                    av_strlcpy(vs->iv_string, ptr, FFMIN(end - ptr + 1, 
sizeof(vs->iv_string)));
                 } else {
                     av_strlcpy(vs->iv_string, ptr, sizeof(vs->iv_string));
                 }
-- 
2.52.0


>From 97c27982c7eee3d8799bbb6559de1cbfc0da7e91 Mon Sep 17 00:00:00 2001
From: Steven Liu <[email protected]>
Date: Thu, 9 Jul 2026 13:04:34 +0800
Subject: [PATCH 2/3] avformat/hls: Enforce protocol checks when opening child
 playlists

Fix: vulnerability:019f3b84-903b-75fb-a8de-fad1c2d7e99c
The parse_playlist() path for opening a new child playlist (in == NULL)
directly called c->ctx->io_open(), bypassing the protocol whitelist and
file-extension checks that open_url() enforces. This allowed child URLs
from a master playlist to use protocols other than file/http/data or to
have disallowed extensions.

Route the !in branch through open_url() so that all child playlists are
subject to the same security policy as segment URLs.

Fixes a security bypass in HLS master playlist parsing.

Founded-by: depthfirst
Signed-off-by: Steven Liu <[email protected]>
---
 libavformat/hls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libavformat/hls.c b/libavformat/hls.c
index e76e68ed51..0e1a1ba49c 100644
--- a/libavformat/hls.c
+++ b/libavformat/hls.c
@@ -857,7 +857,7 @@ static int parse_playlist(HLSContext *c, const char *url,
         if (c->http_persistent)
             av_dict_set(&opts, "multiple_requests", "1", 0);
 
-        ret = c->ctx->io_open(c->ctx, &in, url, AVIO_FLAG_READ, &opts);
+        ret = open_url(c->ctx, &in, url, &opts, NULL, NULL);
         av_dict_free(&opts);
         if (ret < 0)
             return ret;
-- 
2.52.0


>From 9789f4cc6515961bf976189ea1c7601ab9a4229c Mon Sep 17 00:00:00 2001
From: Steven Liu <[email protected]>
Date: Thu, 9 Jul 2026 13:12:26 +0800
Subject: [PATCH 3/3] avformat/hlsenc: Handle extensionless URIs in
 extract_segment_number()

fix: vulnerability:019f3b84-90fb-737a-ae7a-b3e0219266fc
extract_segment_number() used strrchr(filename, '.') and immediately did
dot - 1 without checking for NULL. A segment URI with no extension would
cause undefined behavior (NULL pointer arithmetic) when resuming an
append_list playlist with subtitle variants.

Add a NULL check and return -1 early when no dot is found.

Fixes a crash/UB in HLS muxer resume path.

Founded-by: depthfirst
Signed-off-by: Steven Liu <[email protected]>
---
 libavformat/hlsenc.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c
index 3a8499e3b8..c3db1fc678 100644
--- a/libavformat/hlsenc.c
+++ b/libavformat/hlsenc.c
@@ -1143,7 +1143,12 @@ static int hls_append_segment(struct AVFormatContext *s, 
HLSContext *hls,
 
 static int extract_segment_number(const char *filename) {
     const char *dot = strrchr(filename, '.');
-    const char *num_start = dot - 1;
+    const char *num_start;
+
+    if (!dot)
+        return -1;
+
+    num_start = dot - 1;
 
     while (num_start > filename && *num_start >= '0' && *num_start <= '9') {
         num_start--;
-- 
2.52.0

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

Reply via email to