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]
