This is based on the encoder and a small number of CFHD sample files It should make the decoder more robust against crafted input. Due to the lack of a proper specification it is possible that this may be too strict and may need to be tuned as files not following this ordering are found.
Signed-off-by: Michael Niedermayer <mich...@niedermayer.cc> --- libavcodec/cfhd.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++ libavcodec/cfhd.h | 4 ++ 2 files changed, 158 insertions(+) diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index ea35f03869..6caaeb9c19 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -361,6 +361,151 @@ static int alloc_buffers(AVCodecContext *avctx) return 0; } +typedef struct TagDescriptor { + int16_t previous_marker1; + int16_t previous_marker2; + uint8_t mandatory : 1; + uint8_t single : 1; +} TagDescriptor; + +static TagDescriptor tag_descriptor[LastTag]={ + [SampleType /* 1*/] = { .previous_marker1 = 0x0c0c, .previous_marker2 = -1, }, + [SampleIndexTable /* 2*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [ 3 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [BitstreamMarker /* 4*/] = { }, + [VersionMajor /* 5*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [VersionMinor /* 6*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [VersionRevision /* 7*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [VersionEdit /* 8*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 9 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [TransformType /* 10*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [NumFrames /* 11*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [ChannelCount /* 12*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [WaveletCount /* 13*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [SubbandCount /* 14*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [NumSpatial /* 15*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [FirstWavelet /* 16*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [ 17 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [GroupTrailer /* 18*/] = { .previous_marker1 = 0x0c0c, .single = 1, .mandatory = 0 }, + [FrameType /* 19*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ImageWidth /* 20*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ImageHeight /* 21*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 22 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [FrameIndex /* 23*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 24 ] = { .previous_marker1 = 0x0c0c, .single = 1, .mandatory = 0 }, + [LowpassSubband /* 25*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [NumLevels /* 26*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [LowpassWidth /* 27*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [LowpassHeight /* 28*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [ 29 ] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [ 30 ] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [ 31 ] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [ 32 ] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [PixelOffset /* 33*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [LowpassQuantization/*34*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [LowpassPrecision /* 35*/] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 1 }, + [ 36 ] = { .previous_marker1 = 0x1a4a, .single = 1, .mandatory = 0 }, + [WaveletType /* 37*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [WaveletNumber /* 38*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [WaveletLevel /* 39*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [NumBands /* 40*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [HighpassWidth /* 41*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [HighpassHeight /* 42*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [LowpassBorder /* 43*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [HighpassBorder /* 44*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [LowpassScale /* 45*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [LowpassDivisor /* 46*/] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 1 }, + [ 47 ] = { .previous_marker1 = 0x0d0d, .single = 1, .mandatory = 0 }, + [SubbandNumber /* 48*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [BandWidth /* 49*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [BandHeight /* 50*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [SubbandBand /* 51*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [BandEncoding /* 52*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [Quantization /* 53*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [BandScale /* 54*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [BandHeader /* 55*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [BandTrailer /* 56*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 1 }, + [ChannelNumber /* 62*/] = { .previous_marker1 = 0x0c0c, .single = 1, .mandatory = 0 }, + [ 63 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [ 64 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [ 65 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [ 66 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [SampleFlags /* 68*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [FrameNumber /* 69*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [Precision /* 70*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [InputFormat /* 71*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 1 }, + [BandCodingFlags /* 72*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 0 }, + [ 73 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [PeakLevel /* 74*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 0 }, + [PeakOffsetLow /* 75*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 0 }, + [PeakOffsetHigh /* 76*/] = { .previous_marker1 = 0x0e0e, .single = 1, .mandatory = 0 }, + [Version /* 79*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 80 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 81 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [BandSecondPass /* 82*/] = { }, + [PrescaleTable /* 83*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [EncodedFormat /* 84*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [DisplayHeight /* 85*/] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 91 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 92 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ 93 ] = { .previous_marker1 = -1, .single = 1, .mandatory = 0 }, + [ChannelWidth /* 104*/] = { }, + [ChannelHeight /* 105*/] = { }, +}; + +static int handle_tag_order(CFHDContext *s, int tag, int data) +{ + TagDescriptor *desc; + int atag = abs(tag); + int i; + + // We do not restrict tags outside the enum + if (atag >= LastTag) + return 0; + + desc= &tag_descriptor[atag]; + if (desc->single && s->tag_count[atag]) + return AVERROR_INVALIDDATA; + + if (desc->previous_marker1 && s->previous_marker != desc->previous_marker1) { + if (!desc->previous_marker2 || s->previous_marker != desc->previous_marker2) + return AVERROR_INVALIDDATA; + } else if (tag == BitstreamMarker) { + if (s->previous_marker == -1 && data == 0x1a4a) { + ; + } else if (s->previous_marker == 0x1a4a && data == 0x0f0f) { + ; + } else if (s->previous_marker == 0x0f0f && data == 0x1b4b) { + ; + } else if (s->previous_marker == 0x1b4b && data == 0x0d0d) { + ; + } else if (s->previous_marker == 0x0d0d && data == 0x0e0e) { + ; + } else if (s->previous_marker == 0x0e0e && (data == 0x0c0c || data == 0x0e0e)) { + ; + } else if (s->previous_marker == 0x0c0c && (data == 0x0d0d || data == 0x1a4a)) { + ; + } else + return AVERROR_INVALIDDATA; + + for (i = 0; i<LastTag; i++) { + // Whenever we switch to a new marker we check the mandatory elements of the previous + if (tag_descriptor[i].previous_marker1 == s->previous_marker && tag_descriptor[i].mandatory && !s->tag_count[i]) { + return AVERROR_INVALIDDATA; + } + + if (tag_descriptor[i].previous_marker1 == data) + s->tag_count[i] = 0; + } + s->previous_marker = data; + } else if (!desc->previous_marker1) + return AVERROR_INVALIDDATA; + + s->tag_count[atag]++; + + return 0; +} + static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { @@ -374,6 +519,8 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, init_frame_defaults(s); s->planes = av_pix_fmt_count_planes(s->coded_format); + s->previous_marker = -1; + memset(s->tag_count, 0, sizeof(s->tag_count)); bytestream2_init(&gb, avpkt->data, avpkt->size); @@ -385,6 +532,13 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, uint16_t abstag = abs(tag); int8_t abs_tag8 = abs(tag8); uint16_t data = bytestream2_get_be16(&gb); + + ret = handle_tag_order(s, tag, data); + if (ret < 0) { + av_log(avctx, AV_LOG_DEBUG, "Unexpected TAG %d data %X in %X\n", tag, data, s->previous_marker); + return ret; + } + if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data); } else if (tag == SampleFlags) { diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 8ea91270cd..802c338f13 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -93,6 +93,7 @@ enum CFHDParam { DisplayHeight = 85, ChannelWidth = 104, ChannelHeight = 105, + LastTag, }; #define VLC_BITS 9 @@ -184,6 +185,9 @@ typedef struct CFHDContext { Plane plane[4]; Peak peak; + int previous_marker; + int tag_count[LastTag]; + CFHDDSPContext dsp; } CFHDContext; -- 2.17.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".