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

Fixes: Stack overflow
Found-by: Joshua Rogers <[email protected]>
Fixes: tyKGcmR25mD8


>From 011cbe5fc553f56ab831b284b9859dda297633cb Mon Sep 17 00:00:00 2001
From: Joshua Rogers <[email protected]>
Date: Mon, 31 Aug 2026 15:31:55 +0200
Subject: [PATCH 1/2] avutil/encryption_info: avoid stack exhaustion freeing
 init info list

Fixes: Stack overflow
Found-by: Joshua Rogers <[email protected]>
Fixes: tyKGcmR25mD8
---
 libavutil/encryption_info.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/libavutil/encryption_info.c b/libavutil/encryption_info.c
index a3eb955d2d..6fc3e33842 100644
--- a/libavutil/encryption_info.c
+++ b/libavutil/encryption_info.c
@@ -218,16 +218,19 @@ AVEncryptionInitInfo *av_encryption_init_info_alloc(
 
 void av_encryption_init_info_free(AVEncryptionInitInfo *info)
 {
-    uint32_t i;
-    if (info) {
+    while (info) {
+        AVEncryptionInitInfo *next = info->next;
+        uint32_t i;
+
         for (i = 0; i < info->num_key_ids; i++) {
             av_free(info->key_ids[i]);
         }
-        av_encryption_init_info_free(info->next);
         av_free(info->system_id);
         av_free(info->key_ids);
         av_free(info->data);
         av_free(info);
+
+        info = next;
     }
 }
 
-- 
2.52.0


>From f9fa6b3ef9b0fd17a514f7a5a8378762c02b3e22 Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Mon, 21 Sep 2026 01:13:15 +0200
Subject: [PATCH 2/2] avformat/mov: append pssh init info in place instead of
 re-parsing the side data

Replaces O(n^2) by O(n) implementation

Fixes: Timeout
Found during triage/review of the security report
Fixes: tyKGcmR25mD8
---
 libavformat/isom.h |  1 +
 libavformat/mov.c  | 56 ++++++++++++++++++++++++----------------------
 2 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 5474d700d6..e52c31e96a 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -284,6 +284,7 @@ typedef struct MOVStreamContext {
         unsigned int per_sample_iv_size;  // Either 0, 8, or 16.
         AVEncryptionInfo *default_encrypted_sample;
         MOVEncryptionIndex *encryption_index;
+        unsigned int init_info_allocated_size;
     } cenc;
 
     struct IAMFDemuxContext *iamf;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 8ddedf269b..c5cea09e83 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -8325,10 +8325,11 @@ static int mov_read_saio(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
 
 static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
-    AVEncryptionInitInfo *info, *old_init_info;
+    AVEncryptionInitInfo *info;
     uint8_t **key_ids;
     AVStream *st;
-    const AVPacketSideData *old_side_data;
+    MOVStreamContext *sc;
+    AVPacketSideData *old_side_data = NULL;
     uint8_t *side_data, *extra_data;
     size_t side_data_size;
     int ret = 0;
@@ -8337,6 +8338,7 @@ static int mov_read_pssh(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
     if (c->fc->nb_streams < 1)
         return 0;
     st = c->fc->streams[c->fc->nb_streams-1];
+    sc = st->priv_data;
 
     version = avio_r8(pb); /* version */
     avio_rb24(pb);  /* flags */
@@ -8407,36 +8409,36 @@ static int mov_read_pssh(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
     info->data = extra_data;
     info->data_size = extra_data_size;
 
-    // If there is existing initialization data, append to the list.
-    old_side_data = av_packet_side_data_get(st->codecpar->coded_side_data, 
st->codecpar->nb_coded_side_data,
-                                            AV_PKT_DATA_ENCRYPTION_INIT_INFO);
-    if (old_side_data) {
-        old_init_info = 
av_encryption_init_info_get_side_data(old_side_data->data, old_side_data->size);
-        if (old_init_info) {
-            // Append to the end of the list.
-            for (AVEncryptionInitInfo *cur = old_init_info;; cur = cur->next) {
-                if (!cur->next) {
-                    cur->next = info;
-                    break;
-                }
-            }
-            info = old_init_info;
-        } else {
-            // Assume existing side-data will be valid, so the only error we 
could get is OOM.
-            ret = AVERROR(ENOMEM);
-            goto finish;
-        }
-    }
-
     side_data = av_encryption_init_info_add_side_data(info, &side_data_size);
     if (!side_data) {
         ret = AVERROR(ENOMEM);
         goto finish;
     }
-    if (!av_packet_side_data_add(&st->codecpar->coded_side_data,
-                                 &st->codecpar->nb_coded_side_data,
-                                 AV_PKT_DATA_ENCRYPTION_INIT_INFO,
-                                 side_data, side_data_size, 0))
+
+    for (int i = 0; i < st->codecpar->nb_coded_side_data; i++)
+        if (st->codecpar->coded_side_data[i].type == 
AV_PKT_DATA_ENCRYPTION_INIT_INFO)
+            old_side_data = &st->codecpar->coded_side_data[i];
+
+    // If there is existing initialization data, append the new record to it.
+    if (old_side_data) {
+        size_t record_size = side_data_size - 4;
+        uint8_t *grown = av_fast_realloc(old_side_data->data, 
&sc->cenc.init_info_allocated_size,
+                                         old_side_data->size + record_size);
+        if (!grown) {
+            ret = AVERROR(ENOMEM);
+        } else {
+            memcpy(grown + old_side_data->size, side_data + 4, record_size);
+            AV_WB32(grown, AV_RB32(grown) + 1);
+            old_side_data->data  = grown;
+            old_side_data->size += record_size;
+        }
+        av_free(side_data);
+    } else if (av_packet_side_data_add(&st->codecpar->coded_side_data,
+                                       &st->codecpar->nb_coded_side_data,
+                                       AV_PKT_DATA_ENCRYPTION_INIT_INFO,
+                                       side_data, side_data_size, 0)) {
+        sc->cenc.init_info_allocated_size = side_data_size;
+    } else
         av_free(side_data);
 
 finish:
-- 
2.52.0

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

Reply via email to