Commit 71403a21b0 for ffmpeg
commit 71403a21b02a92b925e26e609e9bd3e48df451cf
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Mon Sep 28 18:41:48 2026 +0200
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
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 42a124edb3..2af2d73df2 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -368,6 +368,8 @@ typedef struct MOVContext {
int has_looked_for_mfra;
int use_tfdt;
MOVFragmentIndex frag_index;
+ uint8_t *pssh_side_data;
+ unsigned int pssh_side_data_allocated;
int atom_depth;
unsigned int aax_mode; ///< 'aax' file has been detected
uint8_t file_key[20];
diff --git a/libavformat/mov.c b/libavformat/mov.c
index f7c12922d9..79bbdb0569 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -8350,12 +8350,12 @@ 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;
- uint8_t *side_data, *extra_data;
- size_t side_data_size;
+ AVPacketSideData *old_side_data = NULL;
+ uint8_t *side_data = NULL, *extra_data;
+ size_t side_data_size = 0;
int ret = 0;
unsigned int version, kid_count, extra_data_size, alloc_size = 0;
@@ -8432,37 +8432,35 @@ 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);
+ 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) {
- 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 = old_side_data->data;
+ side_data_size = old_side_data->size;
}
+ if (!old_side_data || side_data != c->pssh_side_data)
+ c->pssh_side_data_allocated = 0;
- side_data = av_encryption_init_info_add_side_data(info, &side_data_size);
- if (!side_data) {
+ ret = av_encryption_init_info_append_side_data(&side_data, &side_data_size,
+ &c->pssh_side_data_allocated, info);
+ if (ret < 0)
+ goto finish;
+
+ if (old_side_data) {
+ old_side_data->data = side_data;
+ old_side_data->size = side_data_size;
+ } 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)) {
+ av_free(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))
- av_free(side_data);
+ c->pssh_side_data = side_data;
finish:
av_encryption_init_info_free(info);
@@ -12586,6 +12584,7 @@ static int mov_switch_root(AVFormatContext *s, int64_t target, int index)
}
mov->found_mdat = 0;
+ mov->pssh_side_data = NULL;
ret = mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX });
if (ret < 0)