From 682a647df0af169a673175eab13f99c7b58fffbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 22 Oct 2025 12:28:32 +0200 Subject: [PATCH 2/2] lavf/mxfdec: Switch mxf_absolute_bodysid_offset() to std::map This allows us to detect and reject evil files which have been constructed to have overlapping partitions --- libavformat/mxfdec.cpp | 90 +++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/libavformat/mxfdec.cpp b/libavformat/mxfdec.cpp index 522d870981..7a7b824e26 100644 --- a/libavformat/mxfdec.cpp +++ b/libavformat/mxfdec.cpp @@ -47,6 +47,9 @@ #include #include +#include +#include + extern "C" { #include "libavutil/aes.h" #include "libavutil/avstring.h" @@ -334,6 +337,26 @@ typedef struct MXFIndexTable { } MXFIndexTable; struct MXFCppContext { + typedef std::map OffsetMap; //< maps BodyOffset -> MXFPartition* + std::map bodysid_offset_partition_map; //< maps (BodySID, BodyOffset) -> MXFPartition* + + // comparator for whether a given offset is contained within [body_offset, body_offset + essence_length) + struct OffsetInPartitionComp { + bool operator() (const std::pair &a, int64_t b) const { + if (a.second->essence_length) { + // <= because the end of the range is exclusive + return a.second->body_offset + a.second->essence_length <= b; + } else { + // if essence_length == 0 then this partition spans the rest of the file + // this should only happen for the last partition + return false; // we can never be "less than" any given offset + } + } + + bool operator() (int64_t a, const std::pair &b) const { + return a < b.second->body_offset; + } + }; }; /* NOTE: klv_offset is not set (-1) for local keys */ @@ -1880,35 +1903,40 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment */ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t offset, int64_t *offset_out, MXFPartition **partition_out) { - MXFPartition *last_p = NULL; - int a, b, m, m0; - - if (offset < 0) - return AVERROR(EINVAL); - - a = -1; - b = mxf->partitions_count; - - while (b - a > 1) { - m0 = m = (a + b) >> 1; - - while (m < b && mxf->partitions[m].body_sid != body_sid) - m++; - - if (m < b && mxf->partitions[m].body_offset <= offset) - a = m; - else - b = m0; - } - - if (a >= 0) - last_p = &mxf->partitions[a]; + auto &partition_map = mxf->cpp_context->bodysid_offset_partition_map; + auto it = partition_map.find(body_sid); + + if (it != partition_map.end()) { + // find range of partitions within which offset is contained + // there should be exactly one + auto [start, end] = std::equal_range( + it->second.begin(), + it->second.end(), + offset, + MXFCppContext::OffsetInPartitionComp() + ); + auto d = std::distance(start, end); + + if (d > 1) { + // this could happen for evil files - reject them + av_log(mxf->fc, AV_LOG_ERROR, "absolute offset %" PRIX64 " contained in more than one partition\n", offset); + + // log offending partitions + for (; start != end; start++) { + MXFPartition *p = start->second; + av_log(mxf->fc, AV_LOG_ERROR, "BodyOffset %" PRIX64 " BodyOffset+essence_length %" PRIX64 "\n", p->body_offset, p->body_offset + p->essence_length); + } - if (last_p && (!last_p->essence_length || last_p->essence_length > (offset - last_p->body_offset))) { - *offset_out = last_p->essence_offset + (offset - last_p->body_offset); - if (partition_out) - *partition_out = last_p; - return 0; + return AVERROR_INVALIDDATA; + } else if (d == 1) { + MXFPartition *last_p = start->second; + if ((!last_p->essence_length || last_p->essence_length > (offset - last_p->body_offset))) { + *offset_out = last_p->essence_offset + (offset - last_p->body_offset); + if (partition_out) + *partition_out = last_p; + return 0; + } + } } av_log(mxf->fc, AV_LOG_ERROR, @@ -3899,6 +3927,12 @@ int mxf_read_header(AVFormatContext *s) mxf_compute_essence_containers(s); + // set up bodysid_offset_partition_map + for (int x = 0; x < mxf->partitions_count; x++) { + MXFPartition *partition = &mxf->partitions[x]; + mxf->cpp_context->bodysid_offset_partition_map[partition->body_sid][partition->body_offset] = partition; + } + for (int i = 0; i < s->nb_streams; i++) mxf_compute_edit_units_per_packet(mxf, s->streams[i]); -- 2.47.2