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