diff options
Diffstat (limited to 'libavcodec/hnm4video.c')
-rw-r--r-- | libavcodec/hnm4video.c | 93 |
1 files changed, 71 insertions, 22 deletions
diff --git a/libavcodec/hnm4video.c b/libavcodec/hnm4video.c index 700504d..31995bc 100644 --- a/libavcodec/hnm4video.c +++ b/libavcodec/hnm4video.c @@ -3,20 +3,20 @@ * * Copyright (c) 2012 David Kment * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -79,7 +79,7 @@ static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src, if (getbit(&gb, &bitbuf, &bits)) { if (writeoffset >= hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, - "Attempting to write out of bounds"); + "Attempting to write out of bounds\n"); break; } hnm->current[writeoffset++] = bytestream2_get_byte(&gb); @@ -100,11 +100,11 @@ static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src, count += 2; offset += writeoffset; if (offset < 0 || offset + count >= hnm->width * hnm->height) { - av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds"); + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); break; } else if (writeoffset + count >= hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, - "Attempting to write out of bounds"); + "Attempting to write out of bounds\n"); break; } while (count--) { @@ -147,7 +147,8 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s { Hnm4VideoContext *hnm = avctx->priv_data; GetByteContext gb; - uint32_t writeoffset = 0, count, left, offset; + uint32_t writeoffset = 0; + int count, left, offset; uint8_t tag, previous, backline, backward, swap; bytestream2_init(&gb, src, size); @@ -157,7 +158,12 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s if (count == 0) { tag = bytestream2_get_byte(&gb) & 0xE0; tag = tag >> 5; + if (tag == 0) { + if (writeoffset + 2 > hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); + break; + } hnm->current[writeoffset++] = bytestream2_get_byte(&gb); hnm->current[writeoffset++] = bytestream2_get_byte(&gb); } else if (tag == 1) { @@ -168,6 +174,10 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s writeoffset += count; } else if (tag == 3) { count = bytestream2_get_byte(&gb) * 2; + if (writeoffset + count > hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); + break; + } while (count > 0) { hnm->current[writeoffset++] = bytestream2_peek_byte(&gb); count--; @@ -176,6 +186,10 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s } else { break; } + if (writeoffset > hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); + break; + } } else { previous = bytestream2_peek_byte(&gb) & 0x20; backline = bytestream2_peek_byte(&gb) & 0x40; @@ -188,17 +202,28 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s left = count; - if (!backward && offset + count >= hnm->width * hnm->height) { - av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds"); + if (!backward && offset + 2*count > hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); break; - } else if (backward && offset >= hnm->width * hnm->height) { - av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds"); + } else if (backward && offset + 1 >= hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); break; - } else if (writeoffset + count >= hnm->width * hnm->height) { + } else if (writeoffset + 2*count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, - "Attempting to write out of bounds"); + "Attempting to write out of bounds\n"); break; } + if(backward) { + if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) { + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); + break; + } + } else { + if (offset < (!!backline)*(2 * hnm->width - 1)) { + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); + break; + } + } if (previous) { while (left > 0) { @@ -263,6 +288,10 @@ static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src, if (tag == 0) { writeoffset += bytestream2_get_byte(&gb); } else if (tag == 1) { + if (writeoffset + hnm->width >= hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); + break; + } hnm->current[writeoffset] = bytestream2_get_byte(&gb); hnm->current[writeoffset + hnm->width] = bytestream2_get_byte(&gb); writeoffset++; @@ -271,6 +300,10 @@ static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src, } else if (tag == 3) { break; } + if (writeoffset > hnm->width * hnm->height) { + av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); + break; + } } else { delta = bytestream2_peek_byte(&gb) & 0x80; previous = bytestream2_peek_byte(&gb) & 0x40; @@ -279,14 +312,19 @@ static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src, offset = writeoffset; offset += bytestream2_get_le16(&gb); - if (delta) + if (delta) { + if (offset < 0x10000) { + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); + break; + } offset -= 0x10000; + } if (offset + hnm->width + count >= hnm->width * hnm->height) { - av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds"); + av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); break; } else if (writeoffset + hnm->width + count >= hnm->width * hnm->height) { - av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds"); + av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n"); break; } @@ -360,17 +398,23 @@ static int hnm_decode_frame(AVCodecContext *avctx, void *data, int ret; uint16_t chunk_id; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); - return ret; + if (avpkt->size < 8) { + av_log(avctx, AV_LOG_ERROR, "packet too small\n"); + return AVERROR_INVALIDDATA; } chunk_id = AV_RL16(avpkt->data + 4); if (chunk_id == HNM4_CHUNK_ID_PL) { hnm_update_palette(avctx, avpkt->data, avpkt->size); - frame->palette_has_changed = 1; } else if (chunk_id == HNM4_CHUNK_ID_IZ) { + if (avpkt->size < 12) { + av_log(avctx, AV_LOG_ERROR, "packet too small\n"); + return AVERROR_INVALIDDATA; + } + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + unpack_intraframe(avctx, avpkt->data + 12, avpkt->size - 12); memcpy(hnm->previous, hnm->current, hnm->width * hnm->height); if (hnm->version == 0x4a) @@ -383,6 +427,9 @@ static int hnm_decode_frame(AVCodecContext *avctx, void *data, memcpy(frame->data[1], hnm->palette, 256 * 4); *got_frame = 1; } else if (chunk_id == HNM4_CHUNK_ID_IU) { + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + if (hnm->version == 0x4a) { decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8); memcpy(hnm->processed, hnm->current, hnm->width * hnm->height); @@ -427,7 +474,9 @@ static av_cold int hnm_decode_init(AVCodecContext *avctx) hnm->buffer2 = av_mallocz(avctx->width * avctx->height); hnm->processed = av_mallocz(avctx->width * avctx->height); - if (!hnm->buffer1 || !hnm->buffer2 || !hnm->processed) { + if ( !hnm->buffer1 || !hnm->buffer2 || !hnm->processed + || avctx->width * avctx->height == 0 + || avctx->height % 2) { av_log(avctx, AV_LOG_ERROR, "av_mallocz() failed\n"); av_freep(&hnm->buffer1); av_freep(&hnm->buffer2); |