Unified · Split
| @@ -33,22 +33,35 @@ typedef struct TargaContext { · 32 unmodified lines | |||
| 33 | int compression_type; | 33 | int compression_type; |
| 34 | } TargaContext; | 34 | } TargaContext; |
| 35 | 35 | ||
| 36 | static void targa_decode_rle(AVCodecContext *avctx, TargaContext *s, const uint8_t *src, uint8_t *dst, int w, int h, int stride, int bpp) | 36 | #define CHECK_BUFFER_SIZE(buf, buf_end, needed, where) \ |
| 37 | if(buf + needed > buf_end){ \ | ||
| 38 | av_log(avctx, AV_LOG_ERROR, "Problem: unexpected end of data while reading " where "\n"); \ | ||
| 39 | return -1; \ | ||
| 40 | } \ | ||
| 41 | |||
| 42 | static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s, const uint8_t *src, int src_size, uint8_t *dst, int w, int h, int stride, int bpp) | ||
| 37 | { | 43 | { |
| 38 | int i, x, y; | 44 | int i, x, y; |
| 39 | int depth = (bpp + 1) >> 3; | 45 | int depth = (bpp + 1) >> 3; |
| 40 | int type, count; | 46 | int type, count; |
| 41 | int diff; | 47 | int diff; |
| 48 | const uint8_t *src_end = src + src_size; | ||
| 42 | 49 | ||
| 43 | diff = stride - w * depth; | 50 | diff = stride - w * depth; |
| 44 | x = y = 0; | 51 | x = y = 0; |
| 45 | while(y < h){ | 52 | while(y < h){ |
| 53 | CHECK_BUFFER_SIZE(src, src_end, 1, "image type"); | ||
| 46 | type = *src++; | 54 | type = *src++; |
| 47 | count = (type & 0x7F) + 1; | 55 | count = (type & 0x7F) + 1; |
| 48 | type &= 0x80; | 56 | type &= 0x80; |
| 49 | if((x + count > w) && (x + count + 1 > (h - y) * w)){ | 57 | if((x + count > w) && (x + count + 1 > (h - y) * w)){ |
| 50 | av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds: position (%i,%i) size %i\n", x, y, count); | 58 | av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds: position (%i,%i) size %i\n", x, y, count); |
| 51 | return; | 59 | return -1; |
| 60 | } | ||
| 61 | if(type){ | ||
| 62 | CHECK_BUFFER_SIZE(src, src_end, depth, "image data"); | ||
| 63 | }else{ | ||
| 64 | CHECK_BUFFER_SIZE(src, src_end, count * depth, "image data"); | ||
| 52 | } | 65 | } |
| 53 | for(i = 0; i < count; i++){ | 66 | for(i = 0; i < count; i++){ |
| 54 | switch(depth){ | 67 | switch(depth){ |
| @@ -81,6 +94,7 @@ static void targa_decode_rle(AVCodecContext *avctx, TargaContext *s, const uint8 · 26 unmodified lines | |||
| 81 | if(type) | 94 | if(type) |
| 82 | src += depth; | 95 | src += depth; |
| 83 | } | 96 | } |
| 97 | return src_size; | ||
| 84 | } | 98 | } |
| 85 | 99 | ||
| 86 | static int decode_frame(AVCodecContext *avctx, | 100 | static int decode_frame(AVCodecContext *avctx, |
| @@ -88,7 +102,7 @@ static int decode_frame(AVCodecContext *avctx, · 1 unmodified line | |||
| 88 | AVPacket *avpkt) | 102 | AVPacket *avpkt) |
| 89 | { | 103 | { |
| 90 | const uint8_t *buf = avpkt->data; | 104 | const uint8_t *buf = avpkt->data; |
| 91 | int buf_size = avpkt->size; | 105 | const uint8_t *buf_end = avpkt->data + avpkt->size; |
| 92 | TargaContext * const s = avctx->priv_data; | 106 | TargaContext * const s = avctx->priv_data; |
| 93 | AVFrame *picture = data; | 107 | AVFrame *picture = data; |
| 94 | AVFrame * const p= (AVFrame*)&s->picture; | 108 | AVFrame * const p= (AVFrame*)&s->picture; |
| @@ -98,6 +112,7 @@ static int decode_frame(AVCodecContext *avctx, · 3 unmodified lines | |||
| 98 | int first_clr, colors, csize; | 112 | int first_clr, colors, csize; |
| 99 | 113 | ||
| 100 | /* parse image header */ | 114 | /* parse image header */ |
| 115 | CHECK_BUFFER_SIZE(buf, buf_end, 18, "header"); | ||
| 101 | idlen = *buf++; | 116 | idlen = *buf++; |
| 102 | pal = *buf++; | 117 | pal = *buf++; |
| 103 | compr = *buf++; | 118 | compr = *buf++; |
| @@ -111,6 +126,7 @@ static int decode_frame(AVCodecContext *avctx, · 7 unmodified lines | |||
| 111 | bpp = *buf++; | 126 | bpp = *buf++; |
| 112 | flags = *buf++; | 127 | flags = *buf++; |
| 113 | //skip identifier if any | 128 | //skip identifier if any |
| 129 | CHECK_BUFFER_SIZE(buf, buf_end, idlen, "identifiers"); | ||
| 114 | buf += idlen; | 130 | buf += idlen; |
| 115 | s->bpp = bpp; | 131 | s->bpp = bpp; |
| 116 | s->width = w; | 132 | s->width = w; |
| @@ -163,6 +179,7 @@ static int decode_frame(AVCodecContext *avctx, · 46 unmodified lines | |||
| 163 | } | 179 | } |
| 164 | } | 180 | } |
| 165 | if(colors){ | 181 | if(colors){ |
| 182 | size_t pal_size; | ||
| 166 | if((colors + first_clr) > 256){ | 183 | if((colors + first_clr) > 256){ |
| 167 | av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); | 184 | av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); |
| 168 | return -1; | 185 | return -1; |
| @@ -171,8 +188,10 @@ static int decode_frame(AVCodecContext *avctx, · 2 unmodified lines | |||
| 171 | av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); | 188 | av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); |
| 172 | return -1; | 189 | return -1; |
| 173 | } | 190 | } |
| 191 | pal_size = colors * ((csize + 1) >> 3); | ||
| 192 | CHECK_BUFFER_SIZE(buf, buf_end, pal_size, "color table"); | ||
| 174 | if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway | 193 | if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway |
| 175 | buf += colors * ((csize + 1) >> 3); | 194 | buf += pal_size; |
| 176 | else{ | 195 | else{ |
| 177 | int r, g, b, t; | 196 | int r, g, b, t; |
| 178 | int32_t *pal = ((int32_t*)p->data[1]) + first_clr; | 197 | int32_t *pal = ((int32_t*)p->data[1]) + first_clr; |
| @@ -188,9 +207,14 @@ static int decode_frame(AVCodecContext *avctx, · 9 unmodified lines | |||
| 188 | if((compr & (~TGA_RLE)) == TGA_NODATA) | 207 | if((compr & (~TGA_RLE)) == TGA_NODATA) |
| 189 | memset(p->data[0], 0, p->linesize[0] * s->height); | 208 | memset(p->data[0], 0, p->linesize[0] * s->height); |
| 190 | else{ | 209 | else{ |
| 191 | if(compr & TGA_RLE) | 210 | if(compr & TGA_RLE){ |
| 192 | targa_decode_rle(avctx, s, buf, dst, avctx->width, avctx->height, stride, bpp); | 211 | int res = targa_decode_rle(avctx, s, buf, buf_end - buf, dst, avctx->width, avctx->height, stride, bpp); |
| 193 | else{ | 212 | if (res < 0) |
| 213 | return -1; | ||
| 214 | buf += res; | ||
| 215 | }else{ | ||
| 216 | size_t img_size = s->width * ((s->bpp + 1) >> 3); | ||
| 217 | CHECK_BUFFER_SIZE(buf, buf_end, img_size, "image data"); | ||
| 194 | for(y = 0; y < s->height; y++){ | 218 | for(y = 0; y < s->height; y++){ |
| 195 | #if HAVE_BIGENDIAN | 219 | #if HAVE_BIGENDIAN |
| 196 | if((s->bpp + 1) >> 3 == 2){ | 220 | if((s->bpp + 1) >> 3 == 2){ |
| @@ -203,10 +227,10 @@ static int decode_frame(AVCodecContext *avctx, · 6 unmodified lines | |||
| 203 | dst32[x] = AV_RL32(buf + x * 4); | 227 | dst32[x] = AV_RL32(buf + x * 4); |
| 204 | }else | 228 | }else |
| 205 | #endif | 229 | #endif |
| 206 | memcpy(dst, buf, s->width * ((s->bpp + 1) >> 3)); | 230 | memcpy(dst, buf, img_size); |
| 207 | 231 | ||
| 208 | dst += stride; | 232 | dst += stride; |
| 209 | buf += s->width * ((s->bpp + 1) >> 3); | 233 | buf += img_size; |
| 210 | } | 234 | } |
| 211 | } | 235 | } |
| 212 | } | 236 | } |
| @@ -214,7 +238,7 @@ static int decode_frame(AVCodecContext *avctx, · 1 unmodified line | |||
| 214 | *picture= *(AVFrame*)&s->picture; | 238 | *picture= *(AVFrame*)&s->picture; |
| 215 | *data_size = sizeof(AVPicture); | 239 | *data_size = sizeof(AVPicture); |
| 216 | 240 | ||
| 217 | return buf_size; | 241 | return avpkt->size; |
| 218 | } | 242 | } |
| 219 | 243 | ||
| 220 | static av_cold int targa_init(AVCodecContext *avctx){ | 244 | static av_cold int targa_init(AVCodecContext *avctx){ |