diff options
author | Andreas Rheinhardt via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> | 2019-03-27 12:18:44 +0100 |
---|---|---|
committer | Michael Niedermayer <michael@niedermayer.cc> | 2019-04-05 12:05:47 +0200 |
commit | 18a851aca766ff8c7199c9e0c37d8fa642e41920 (patch) | |
tree | 9b6c5ec2e3888809c0f06c21d0c18ca3d6f0c418 /libavformat/matroskadec.c | |
parent | 8e3b01e20ebd82528c3302d6756f3c6dffa4bfb2 (diff) | |
download | ffmpeg-18a851aca766ff8c7199c9e0c37d8fa642e41920.tar.gz |
avformat/matroskadec: Improve length check
The earlier code had three flaws:
1. The case of an unknown-sized element inside a finite-sized element
(which is against the specifications) was not caught.
2. The error message wasn't helpful: It compared the length of the child
with the offset of the end of the parent and claimed that the first
exceeds the latter, although that is not necessarily true.
3. Unknown-sized elements that are not parsed can't be skipped. Given
that according to the Matroska specifications only the segment and the
clusters can be of unknown-size, this is handled by not allowing any
other units to have infinite size whereas the earlier code would seek
back by 1 byte upon encountering an infinite-size element that ought
to be skipped.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@googlemail.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavformat/matroskadec.c')
-rw-r--r-- | libavformat/matroskadec.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 81e9bb9bff..cba2b3d1f8 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -1203,11 +1203,29 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; AVIOContext *pb = matroska->ctx->pb; int64_t pos = avio_tell(pb); - if (level->length != EBML_UNKNOWN_LENGTH && - (pos + length) > (level->start + level->length)) { + + if (length != EBML_UNKNOWN_LENGTH && + level->length != EBML_UNKNOWN_LENGTH) { + uint64_t elem_end = pos + length, + level_end = level->start + level->length; + + if (level_end < elem_end) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Element at 0x%"PRIx64" ending at 0x%"PRIx64" exceeds " + "containing master element ending at 0x%"PRIx64"\n", + pos, elem_end, level_end); + return AVERROR_INVALIDDATA; + } + } else if (level->length != EBML_UNKNOWN_LENGTH) { + av_log(matroska->ctx, AV_LOG_ERROR, "Unknown-sized element " + "at 0x%"PRIx64" inside parent with finite size\n", pos); + return AVERROR_INVALIDDATA; + } else if (length == EBML_UNKNOWN_LENGTH && id != MATROSKA_ID_CLUSTER) { + // According to the specifications only clusters and segments + // are allowed to be unknown-sized. av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid length 0x%"PRIx64" > 0x%"PRIx64" in parent\n", - length, level->start + level->length); + "Found unknown-sized element other than a cluster at " + "0x%"PRIx64". Dropping the invalid element.\n", pos); return AVERROR_INVALIDDATA; } } |