X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fiff.c;h=79f6215c7700bef2008cc4c06680024b1b997ddd;hb=1ec87f50f42a16f9228444dc08aa8264879f61e1;hp=33cf2e3a947858a420474157880ffb774ab0fc71;hpb=73d193d1d0ff62a029a905d1404c0fd357f4c880;p=ffmpeg diff --git a/libavcodec/iff.c b/libavcodec/iff.c index 33cf2e3a947..79f6215c770 100644 --- a/libavcodec/iff.c +++ b/libavcodec/iff.c @@ -111,23 +111,23 @@ static const uint64_t plane8_lut[8][256] = { LUT8(4), LUT8(5), LUT8(6), LUT8(7), }; -#define LUT32(plane) { \ - 0, 0, 0, 0, \ - 0, 0, 0, 1 << plane, \ - 0, 0, 1 << plane, 0, \ - 0, 0, 1 << plane, 1 << plane, \ - 0, 1 << plane, 0, 0, \ - 0, 1 << plane, 0, 1 << plane, \ - 0, 1 << plane, 1 << plane, 0, \ - 0, 1 << plane, 1 << plane, 1 << plane, \ - 1 << plane, 0, 0, 0, \ - 1 << plane, 0, 0, 1 << plane, \ - 1 << plane, 0, 1 << plane, 0, \ - 1 << plane, 0, 1 << plane, 1 << plane, \ - 1 << plane, 1 << plane, 0, 0, \ - 1 << plane, 1 << plane, 0, 1 << plane, \ - 1 << plane, 1 << plane, 1 << plane, 0, \ - 1 << plane, 1 << plane, 1 << plane, 1 << plane, \ +#define LUT32(plane) { \ + 0, 0, 0, 0, \ + 0, 0, 0, 1U << plane, \ + 0, 0, 1U << plane, 0, \ + 0, 0, 1U << plane, 1U << plane, \ + 0, 1U << plane, 0, 0, \ + 0, 1U << plane, 0, 1U << plane, \ + 0, 1U << plane, 1U << plane, 0, \ + 0, 1U << plane, 1U << plane, 1U << plane, \ + 1U << plane, 0, 0, 0, \ + 1U << plane, 0, 0, 1U << plane, \ + 1U << plane, 0, 1U << plane, 0, \ + 1U << plane, 0, 1U << plane, 1U << plane, \ + 1U << plane, 1U << plane, 0, 0, \ + 1U << plane, 1U << plane, 0, 1U << plane, \ + 1U << plane, 1U << plane, 1U << plane, 0, \ + 1U << plane, 1U << plane, 1U << plane, 1U << plane, \ } // 32 planes * 4-bit mask * 4 lookup tables each @@ -180,6 +180,10 @@ static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal) pal[i] = 0xFF000000 | gray2rgb((i * 255) >> avctx->bits_per_coded_sample); } if (s->masking == MASK_HAS_MASK) { + if ((1 << avctx->bits_per_coded_sample) < count) { + avpriv_request_sample(avctx, "overlapping mask"); + return AVERROR_PATCHWELCOME; + } memcpy(pal + (1 << avctx->bits_per_coded_sample), pal, count * 4); for (i = 0; i < count; i++) pal[i] &= 0xFFFFFF; @@ -280,6 +284,16 @@ static int extract_header(AVCodecContext *const avctx, for (i = 0; i < 16; i++) s->tvdc[i] = bytestream_get_be16(&buf); + if (s->ham) { + if (s->bpp > 8) { + av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham); + return AVERROR_INVALIDDATA; + } else if (s->ham != (s->bpp > 6 ? 6 : 4)) { + av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u, BPP: %u\n", s->ham, s->bpp); + return AVERROR_INVALIDDATA; + } + } + if (s->masking == MASK_HAS_MASK) { if (s->bpp >= 8 && !s->ham) { avctx->pix_fmt = AV_PIX_FMT_RGB32; @@ -307,10 +321,9 @@ static int extract_header(AVCodecContext *const avctx, if (!s->bpp || s->bpp > 32) { av_log(avctx, AV_LOG_ERROR, "Invalid number of bitplanes: %u\n", s->bpp); return AVERROR_INVALIDDATA; - } else if (s->ham >= 8) { - av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham); - return AVERROR_INVALIDDATA; } + if (s->video_size && s->planesize * s->bpp * avctx->height > s->video_size) + return AVERROR_INVALIDDATA; av_freep(&s->ham_buf); av_freep(&s->ham_palbuf); @@ -319,13 +332,17 @@ static int extract_header(AVCodecContext *const avctx, int i, count = FFMIN(palette_size / 3, 1 << s->ham); int ham_count; const uint8_t *const palette = avctx->extradata + AV_RB16(avctx->extradata); + int extra_space = 1; + + if (avctx->codec_tag == MKTAG('P', 'B', 'M', ' ') && s->ham == 4) + extra_space = 4; s->ham_buf = av_malloc((s->planesize * 8) + AV_INPUT_BUFFER_PADDING_SIZE); if (!s->ham_buf) return AVERROR(ENOMEM); ham_count = 8 * (1 << s->ham); - s->ham_palbuf = av_malloc((ham_count << !!(s->masking == MASK_HAS_MASK)) * sizeof (uint32_t) + AV_INPUT_BUFFER_PADDING_SIZE); + s->ham_palbuf = av_malloc(extra_space * (ham_count << !!(s->masking == MASK_HAS_MASK)) * sizeof (uint32_t) + AV_INPUT_BUFFER_PADDING_SIZE); if (!s->ham_palbuf) { av_freep(&s->ham_buf); return AVERROR(ENOMEM); @@ -371,6 +388,8 @@ static av_cold int decode_end(AVCodecContext *avctx) av_freep(&s->planebuf); av_freep(&s->ham_buf); av_freep(&s->ham_palbuf); + av_freep(&s->mask_buf); + av_freep(&s->mask_palbuf); av_freep(&s->video[0]); av_freep(&s->video[1]); av_freep(&s->pal); @@ -421,6 +440,8 @@ static av_cold int decode_init(AVCodecContext *avctx) if (avctx->codec_tag == MKTAG('A', 'N', 'I', 'M')) { s->video_size = FFALIGN(avctx->width, 2) * avctx->height * s->bpp; + if (!s->video_size) + return AVERROR_INVALIDDATA; s->video[0] = av_calloc(FFALIGN(avctx->width, 2) * avctx->height, s->bpp); s->video[1] = av_calloc(FFALIGN(avctx->width, 2) * avctx->height, s->bpp); s->pal = av_calloc(256, sizeof(*s->pal)); @@ -443,11 +464,12 @@ static av_cold int decode_init(AVCodecContext *avctx) */ static void decodeplane8(uint8_t *dst, const uint8_t *buf, int buf_size, int plane) { - const uint64_t *lut = plane8_lut[plane]; + const uint64_t *lut; if (plane >= 8) { av_log(NULL, AV_LOG_WARNING, "Ignoring extra planes beyond 8\n"); return; } + lut = plane8_lut[plane]; do { uint64_t v = AV_RN64A(dst) | lut[*buf++]; AV_WN64A(dst, v); @@ -695,13 +717,15 @@ static void decode_deep_rle32(uint8_t *dst, const uint8_t *src, int src_size, in { const uint8_t *src_end = src + src_size; int x = 0, y = 0, i; - while (src + 5 <= src_end) { + while (src_end - src >= 5) { int opcode; opcode = *(int8_t *)src++; if (opcode >= 0) { int size = opcode + 1; for (i = 0; i < size; i++) { - int length = FFMIN(size - i, width); + int length = FFMIN(size - i, width - x); + if (src_end - src < length * 4) + return; memcpy(dst + y*linesize + x * 4, src, length * 4); src += length * 4; x += length; @@ -1130,6 +1154,9 @@ static void decode_long_vertical_delta(uint8_t *dst, x = bytestream2_get_be32(&dgb); } + if (ofsdst + (opcode - 1LL) * dstpitch > bytestream2_size_p(&pb)) + return; + while (opcode) { bytestream2_seek_p(&pb, ofsdst, SEEK_SET); if (h && (j == (ncolumns - 1))) { @@ -1270,6 +1297,9 @@ static void decode_long_vertical_delta2(uint8_t *dst, x = bytestream2_get_be32(&gb); } + if (ofsdst + (opcode - 1LL) * dstpitch > bytestream2_size_p(&pb)) + return; + while (opcode && bytestream2_get_bytes_left_p(&pb) > 1) { bytestream2_seek_p(&pb, ofsdst, SEEK_SET); if (h && (j == ncolumns - 1)) @@ -1332,6 +1362,9 @@ static void decode_delta_d(uint8_t *dst, bytestream2_init(&gb, buf + ofssrc, buf_end - (buf + ofssrc)); entries = bytestream2_get_be32(&gb); + if (entries * 8LL > bytestream2_get_bytes_left(&gb)) + return; + while (entries && bytestream2_get_bytes_left(&gb) >= 8) { int32_t opcode = bytestream2_get_be32(&gb); unsigned offset = bytestream2_get_be32(&gb); @@ -1339,17 +1372,18 @@ static void decode_delta_d(uint8_t *dst, bytestream2_seek_p(&pb, (offset / planepitch_byte) * pitch + (offset % planepitch_byte) + k * planepitch, SEEK_SET); if (opcode >= 0) { uint32_t x = bytestream2_get_be32(&gb); + if (opcode && 4 + (opcode - 1LL) * pitch > bytestream2_get_bytes_left_p(&pb)) + continue; while (opcode && bytestream2_get_bytes_left_p(&pb) > 0) { bytestream2_put_be32(&pb, x); bytestream2_skip_p(&pb, pitch - 4); opcode--; } } else { - opcode = -opcode; while (opcode && bytestream2_get_bytes_left(&gb) > 0) { bytestream2_put_be32(&pb, bytestream2_get_be32(&gb)); bytestream2_skip_p(&pb, pitch - 4); - opcode--; + opcode++; } } entries--; @@ -1512,7 +1546,7 @@ static int decode_frame(AVCodecContext *avctx, buf_size -= bytestream2_tell(gb); desc = av_pix_fmt_desc_get(avctx->pix_fmt); - if (!s->init && avctx->bits_per_coded_sample <= 8 && + if (!s->init && avctx->bits_per_coded_sample <= 8 - (s->masking == MASK_HAS_MASK) && avctx->pix_fmt == AV_PIX_FMT_PAL8) { if ((res = cmap_read_palette(avctx, (uint32_t *)frame->data[1])) < 0) return res;