From 5e5e69d0787ae4939f3f8e8d6c0342310eda28ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Tue, 20 Dec 2011 17:38:27 +0100 Subject: [PATCH 1/8] mxfdec: Check for NULL component This fixes SIGSEGV with zzuf1.mxf --- libavformat/mxfdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index b6a63c90a2..59c8b4016b 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1276,7 +1276,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) break; } } - if (!source_track) + if (!source_track || !component) continue; if (!(source_track->sequence = mxf_resolve_strong_ref(mxf, &source_track->sequence_ref, Sequence))) { From 2116e4ba917748c0985be2347d400ba0f3fe6c64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Tue, 20 Dec 2011 17:39:59 +0100 Subject: [PATCH 2/8] mxfdec: Check url_feof() in mxf_read_local_tags() This fixes the infinite loop with zzuf2.mxf --- libavformat/mxfdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 59c8b4016b..8d60fe76f4 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1437,7 +1437,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (!ctx) return -1; - while (avio_tell(pb) + 4 < klv_end) { + while (avio_tell(pb) + 4 < klv_end && !url_feof(pb)) { int tag = avio_rb16(pb); int size = avio_rb16(pb); /* KLV specified by 0x53 */ uint64_t next = avio_tell(pb) + size; From 4ae7d4517048fb5ba64069ad332c2a555d86a8e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Tue, 20 Dec 2011 18:04:13 +0100 Subject: [PATCH 3/8] mxfdec: Fix infinite loop in mxf_packet_timestamps() This can happen if an index table segment has a very large IndexStartPosition. zzuf3.mxf is an example of such a file. --- libavformat/mxfdec.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 8d60fe76f4..4a49907a69 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1712,7 +1712,7 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) */ static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) { - int64_t next_ofs; + int64_t last_ofs = -1, next_ofs; MXFIndexTable *t = &mxf->index_tables[0]; /* this is called from the OP1a demuxing logic, which means there may be no index tables */ @@ -1724,9 +1724,17 @@ static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) break; + if (next_ofs <= last_ofs) { + /* large next_ofs didn't change or current_edit_unit wrapped around + * this fixes the infinite loop on zzuf3.mxf */ + av_log(mxf->fc, AV_LOG_ERROR, "next_ofs didn't change. not deriving packet timestamps\n"); + return; + } + if (next_ofs > pkt->pos) break; + last_ofs = next_ofs; mxf->current_edit_unit++; } From 184f479096dabcb1eafd9c661304f410a76780ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Tue, 20 Dec 2011 18:11:10 +0100 Subject: [PATCH 4/8] mxfdec: Move the current_partition check inside mxf_read_header() This fixes SIGSEGV on files where this is actually the case, such as zzuf4.mxf --- libavformat/mxfdec.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 4a49907a69..5035a2fc2b 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1500,11 +1500,6 @@ static int mxf_parse_handle_essence(MXFContext *mxf) AVIOContext *pb = mxf->fc->pb; int64_t ret; - if (!mxf->current_partition) { - av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to PartitionPack\n"); - return AVERROR_INVALIDDATA; - } - if (mxf->parsing_backward) { return mxf_seek_to_previous_partition(mxf); } else { @@ -1620,6 +1615,12 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) || IS_KLV_KEY(klv.key, mxf_system_item_key)) { + + if (!mxf->current_partition) { + av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n"); + return AVERROR_INVALIDDATA; + } + if (!mxf->current_partition->essence_offset) { /* for OP1a we compute essence_offset * for OPAtom we point essence_offset after the KL (usually op1a_essence_offset + 20 or 25) From e7839602f469eb9dd5e1341d780c0c1667ac89ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 21 Dec 2011 10:49:27 +0100 Subject: [PATCH 5/8] mxfdec: Never seek back in local sets and KLVs Specially crafted files can lead the parsing code to take too long. We fix a lot of these problems by not allowing local tags to extend past the end of the set and not allowing other KLVs to be read past the end of themselves. --- libavformat/mxfdec.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 5035a2fc2b..e1363747a9 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1464,6 +1464,13 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF else if (read_child(ctx, pb, tag, size, uid, -1) < 0) return -1; + /* accept the 64k local set limit being exceeded (Avid) + * don't accept it extending past the end of the KLV though (zzuf5.mxf) */ + if (avio_tell(pb) > klv_end) { + av_log(mxf->fc, AV_LOG_ERROR, "local tag %#04x extends past end of local set @ %#"PRIx64"\n", + tag, klv->offset); + return AVERROR_INVALIDDATA; + } else if (avio_tell(pb) <= next) /* only seek forward, else this can loop for a long time */ avio_seek(pb, next, SEEK_SET); } if (ctx_size) ctx->type = type; @@ -1667,6 +1674,14 @@ static int mxf_read_header(AVFormatContext *s, AVFormatParameters *ap) } else { uint64_t next = avio_tell(s->pb) + klv.length; res = metadata->read(mxf, s->pb, 0, klv.length, klv.key, klv.offset); + + /* only seek forward, else this can loop for a long time */ + if (avio_tell(s->pb) > next) { + av_log(s, AV_LOG_ERROR, "read past end of KLV @ %#"PRIx64"\n", + klv.offset); + return AVERROR_INVALIDDATA; + } + avio_seek(s->pb, next, SEEK_SET); } if (res < 0) { From 46d65fb8a574465499a470d0c34a30902e45176a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 21 Dec 2011 10:56:59 +0100 Subject: [PATCH 6/8] mxfdec: Sanity check PreviousPartition Without this certain files could get the demuxer stuck in a loop --- libavformat/mxfdec.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index e1363747a9..15c2a21e1d 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -479,6 +479,13 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size partition->previous_partition, footer_partition, partition->index_sid, partition->body_sid); + /* sanity check PreviousPartition if set */ + if (partition->previous_partition && + mxf->run_in + partition->previous_partition >= klv_offset) { + av_log(mxf->fc, AV_LOG_ERROR, "PreviousPartition points to this partition or forward\n"); + return AVERROR_INVALIDDATA; + } + if (op[12] == 1 && op[13] == 1) mxf->op = OP1a; else if (op[12] == 1 && op[13] == 2) mxf->op = OP1b; else if (op[12] == 1 && op[13] == 3) mxf->op = OP1c; From 0cd21ddaed5bd9e55fd4bb46f0a9e101b631cfc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 21 Dec 2011 11:58:01 +0100 Subject: [PATCH 7/8] mxfdec: Zero nb_ptses in mxf_compute_ptses_fake_index() This fixes SIGSEGV on files with both CBR and VBR index segments (zzuf6.mxf). --- libavformat/mxfdec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 15c2a21e1d..50dc3a8053 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1028,8 +1028,10 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta for (i = 0; i < index_table->nb_segments; i++) { MXFIndexTableSegment *s = index_table->segments[i]; - if (!s->nb_index_entries) + if (!s->nb_index_entries) { + index_table->nb_ptses = 0; return 0; /* no TemporalOffsets */ + } index_table->nb_ptses += s->index_duration; } From cc1dda851b082826e652d698a9ca4738fc2a0ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomas=20H=C3=A4rdin?= Date: Wed, 21 Dec 2011 12:00:04 +0100 Subject: [PATCH 8/8] mxfdec: Don't crash in mxf_packet_timestamps() if current_edit_unit overflows --- libavformat/mxfdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 50dc3a8053..47fa81d495 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -1745,7 +1745,7 @@ static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) return; /* find mxf->current_edit_unit so that the next edit unit starts ahead of pkt->pos */ - for (;;) { + while (mxf->current_edit_unit >= 0) { if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) break; @@ -1763,7 +1763,7 @@ static void mxf_packet_timestamps(MXFContext *mxf, AVPacket *pkt) mxf->current_edit_unit++; } - if (mxf->current_edit_unit >= t->nb_ptses) + if (mxf->current_edit_unit < 0 || mxf->current_edit_unit >= t->nb_ptses) return; pkt->dts = mxf->current_edit_unit + t->first_dts;