Browse code

tiffdec: use bytestream2 to simplify overread/overwrite protection

Based on a patch by Paul B Mahol <onemda@gmail.com>

CC:libav-stable@libav.org

Justin Ruggles authored on 2013/09/30 08:47:55
Showing 1 changed files
... ...
@@ -34,6 +34,7 @@
34 34
 #include "libavutil/intreadwrite.h"
35 35
 #include "libavutil/imgutils.h"
36 36
 #include "avcodec.h"
37
+#include "bytestream.h"
37 38
 #include "faxcompr.h"
38 39
 #include "internal.h"
39 40
 #include "lzw.h"
... ...
@@ -42,6 +43,7 @@
42 42
 
43 43
 typedef struct TiffContext {
44 44
     AVCodecContext *avctx;
45
+    GetByteContext gb;
45 46
 
46 47
     int width, height;
47 48
     unsigned int bpp, bppcount;
... ...
@@ -56,37 +58,27 @@ typedef struct TiffContext {
56 56
 
57 57
     int strips, rps, sstype;
58 58
     int sot;
59
-    const uint8_t *stripdata;
60
-    const uint8_t *stripsizes;
61
-    int stripsize, stripoff;
59
+    int stripsizesoff, stripsize, stripoff, strippos;
62 60
     LZWState *lzw;
63 61
 } TiffContext;
64 62
 
65
-static unsigned tget_short(const uint8_t **p, int le)
63
+static unsigned tget_short(GetByteContext *gb, int le)
66 64
 {
67
-    unsigned v = le ? AV_RL16(*p) : AV_RB16(*p);
68
-    *p += 2;
69
-    return v;
65
+    return le ? bytestream2_get_le16(gb) : bytestream2_get_be16(gb);
70 66
 }
71 67
 
72
-static unsigned tget_long(const uint8_t **p, int le)
68
+static unsigned tget_long(GetByteContext *gb, int le)
73 69
 {
74
-    unsigned v = le ? AV_RL32(*p) : AV_RB32(*p);
75
-    *p += 4;
76
-    return v;
70
+    return le ? bytestream2_get_le32(gb) : bytestream2_get_be32(gb);
77 71
 }
78 72
 
79
-static unsigned tget(const uint8_t **p, int type, int le)
73
+static unsigned tget(GetByteContext *gb, int type, int le)
80 74
 {
81 75
     switch (type) {
82
-    case TIFF_BYTE:
83
-        return *(*p)++;
84
-    case TIFF_SHORT:
85
-        return tget_short(p, le);
86
-    case TIFF_LONG:
87
-        return tget_long(p, le);
88
-    default:
89
-        return UINT_MAX;
76
+    case TIFF_BYTE:  return bytestream2_get_byte(gb);
77
+    case TIFF_SHORT: return tget_short(gb, le);
78
+    case TIFF_LONG:  return tget_long(gb, le);
79
+    default:         return UINT_MAX;
90 80
     }
91 81
 }
92 82
 
... ...
@@ -176,9 +168,9 @@ static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride,
176 176
 static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
177 177
                              const uint8_t *src, int size, int lines)
178 178
 {
179
+    PutByteContext pb;
179 180
     int c, line, pixels, code, ret;
180
-    const uint8_t *ssrc = src;
181
-    int width           = ((s->width * s->bpp) + 7) >> 3;
181
+    int width = ((s->width * s->bpp) + 7) >> 3;
182 182
 
183 183
     if (size <= 0)
184 184
         return AVERROR_INVALIDDATA;
... ...
@@ -198,69 +190,56 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
198 198
             av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n");
199 199
             return ret;
200 200
         }
201
+        for (line = 0; line < lines; line++) {
202
+            pixels = ff_lzw_decode(s->lzw, dst, width);
203
+            if (pixels < width) {
204
+                av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n",
205
+                       pixels, width);
206
+                return AVERROR_INVALIDDATA;
207
+            }
208
+            dst += stride;
209
+        }
210
+        return 0;
201 211
     }
202 212
     if (s->compr == TIFF_CCITT_RLE ||
203 213
         s->compr == TIFF_G3        ||
204 214
         s->compr == TIFF_G4) {
205 215
         return tiff_unpack_fax(s, dst, stride, src, size, lines);
206 216
     }
217
+
218
+    bytestream2_init(&s->gb, src, size);
219
+    bytestream2_init_writer(&pb, dst, stride * lines);
220
+
207 221
     for (line = 0; line < lines; line++) {
208
-        if (src - ssrc > size) {
209
-            av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n");
210
-            return AVERROR_INVALIDDATA;
211
-        }
222
+        if (bytestream2_get_bytes_left(&s->gb) == 0 || bytestream2_get_eof(&pb))
223
+            break;
224
+        bytestream2_seek_p(&pb, stride * line, SEEK_SET);
212 225
         switch (s->compr) {
213 226
         case TIFF_RAW:
214
-            if (ssrc + size - src < width)
215
-                return AVERROR_INVALIDDATA;
216 227
             if (!s->fill_order) {
217
-                memcpy(dst, src, width);
228
+                bytestream2_copy_buffer(&pb, &s->gb, width);
218 229
             } else {
219 230
                 int i;
220 231
                 for (i = 0; i < width; i++)
221
-                    dst[i] = ff_reverse[src[i]];
232
+                    bytestream2_put_byte(&pb, ff_reverse[bytestream2_get_byte(&s->gb)]);
222 233
             }
223
-            src += width;
224 234
             break;
225 235
         case TIFF_PACKBITS:
226 236
             for (pixels = 0; pixels < width;) {
227
-                if (ssrc + size - src < 2)
228
-                    return AVERROR_INVALIDDATA;
229
-                code = (int8_t) *src++;
237
+                code = ff_u8_to_s8(bytestream2_get_byte(&s->gb));
230 238
                 if (code >= 0) {
231 239
                     code++;
232
-                    if (pixels + code > width ||
233
-                        ssrc + size - src < code) {
234
-                        av_log(s->avctx, AV_LOG_ERROR,
235
-                               "Copy went out of bounds\n");
236
-                        return AVERROR_INVALIDDATA;
237
-                    }
238
-                    memcpy(dst + pixels, src, code);
239
-                    src    += code;
240
+                    bytestream2_copy_buffer(&pb, &s->gb, code);
240 241
                     pixels += code;
241 242
                 } else if (code != -128) { // -127..-1
242 243
                     code = (-code) + 1;
243
-                    if (pixels + code > width) {
244
-                        av_log(s->avctx, AV_LOG_ERROR,
245
-                               "Run went out of bounds\n");
246
-                        return AVERROR_INVALIDDATA;
247
-                    }
248
-                    c = *src++;
249
-                    memset(dst + pixels, c, code);
244
+                    c    = bytestream2_get_byte(&s->gb);
245
+                    bytestream2_set_buffer(&pb, c, code);
250 246
                     pixels += code;
251 247
                 }
252 248
             }
253 249
             break;
254
-        case TIFF_LZW:
255
-            pixels = ff_lzw_decode(s->lzw, dst, width);
256
-            if (pixels < width) {
257
-                av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n",
258
-                       pixels, width);
259
-                return AVERROR_INVALIDDATA;
260
-            }
261
-            break;
262 250
         }
263
-        dst += stride;
264 251
     }
265 252
     return 0;
266 253
 }
... ...
@@ -317,20 +296,19 @@ static int init_image(TiffContext *s, AVFrame *frame)
317 317
     return 0;
318 318
 }
319 319
 
320
-static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
321
-                           const uint8_t *buf, const uint8_t *end_buf)
320
+static int tiff_decode_tag(TiffContext *s)
322 321
 {
323 322
     unsigned tag, type, count, off, value = 0;
324
-    int i;
323
+    int i, start;
325 324
     uint32_t *pal;
326
-    const uint8_t *rp, *gp, *bp;
327 325
 
328
-    if (end_buf - buf < 12)
326
+    if (bytestream2_get_bytes_left(&s->gb) < 12)
329 327
         return AVERROR_INVALIDDATA;
330
-    tag   = tget_short(&buf, s->le);
331
-    type  = tget_short(&buf, s->le);
332
-    count = tget_long(&buf, s->le);
333
-    off   = tget_long(&buf, s->le);
328
+    tag   = tget_short(&s->gb, s->le);
329
+    type  = tget_short(&s->gb, s->le);
330
+    count = tget_long(&s->gb, s->le);
331
+    off   = tget_long(&s->gb, s->le);
332
+    start = bytestream2_tell(&s->gb);
334 333
 
335 334
     if (type == 0 || type >= FF_ARRAY_ELEMS(type_sizes)) {
336 335
         av_log(s->avctx, AV_LOG_DEBUG, "Unknown tiff type (%u) encountered\n",
... ...
@@ -342,34 +320,26 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
342 342
         switch (type) {
343 343
         case TIFF_BYTE:
344 344
         case TIFF_SHORT:
345
-            buf  -= 4;
346
-            value = tget(&buf, type, s->le);
347
-            buf   = NULL;
345
+            bytestream2_seek(&s->gb, -4, SEEK_CUR);
346
+            value = tget(&s->gb, type, s->le);
348 347
             break;
349 348
         case TIFF_LONG:
350 349
             value = off;
351
-            buf   = NULL;
352 350
             break;
353 351
         case TIFF_STRING:
354 352
             if (count <= 4) {
355
-                buf -= 4;
353
+                bytestream2_seek(&s->gb, -4, SEEK_CUR);
356 354
                 break;
357 355
             }
358 356
         default:
359 357
             value = UINT_MAX;
360
-            buf   = start + off;
358
+            bytestream2_seek(&s->gb, off, SEEK_SET);
361 359
         }
362 360
     } else {
363 361
         if (count <= 4 && type_sizes[type] * count <= 4)
364
-            buf -= 4;
362
+            bytestream2_seek(&s->gb, -4, SEEK_CUR);
365 363
         else
366
-            buf = start + off;
367
-    }
368
-
369
-    if (buf && (buf < start || buf > end_buf)) {
370
-        av_log(s->avctx, AV_LOG_ERROR,
371
-               "Tag referencing position outside the image\n");
372
-        return AVERROR_INVALIDDATA;
364
+            bytestream2_seek(&s->gb, off, SEEK_SET);
373 365
     }
374 366
 
375 367
     switch (tag) {
... ...
@@ -398,8 +368,8 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
398 398
             case TIFF_SHORT:
399 399
             case TIFF_LONG:
400 400
                 s->bpp = 0;
401
-                for (i = 0; i < count && buf < end_buf; i++)
402
-                    s->bpp += tget(&buf, type, s->le);
401
+                for (i = 0; i < count; i++)
402
+                    s->bpp += tget(&s->gb, type, s->le);
403 403
                 break;
404 404
             default:
405 405
                 s->bpp = -1;
... ...
@@ -459,35 +429,25 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
459 459
         break;
460 460
     case TIFF_STRIP_OFFS:
461 461
         if (count == 1) {
462
-            s->stripdata = NULL;
463
-            s->stripoff  = value;
462
+            s->strippos = 0;
463
+            s->stripoff = value;
464 464
         } else
465
-            s->stripdata = start + off;
465
+            s->strippos = off;
466 466
         s->strips = count;
467 467
         if (s->strips == 1)
468 468
             s->rps = s->height;
469 469
         s->sot = type;
470
-        if (s->stripdata > end_buf) {
471
-            av_log(s->avctx, AV_LOG_ERROR,
472
-                   "Tag referencing position outside the image\n");
473
-            return AVERROR_INVALIDDATA;
474
-        }
475 470
         break;
476 471
     case TIFF_STRIP_SIZE:
477 472
         if (count == 1) {
478
-            s->stripsizes = NULL;
479
-            s->stripsize  = value;
480
-            s->strips     = 1;
473
+            s->stripsizesoff = 0;
474
+            s->stripsize     = value;
475
+            s->strips        = 1;
481 476
         } else {
482
-            s->stripsizes = start + off;
477
+            s->stripsizesoff = off;
483 478
         }
484 479
         s->strips = count;
485 480
         s->sstype = type;
486
-        if (s->stripsizes > end_buf) {
487
-            av_log(s->avctx, AV_LOG_ERROR,
488
-                   "Tag referencing position outside the image\n");
489
-            return AVERROR_INVALIDDATA;
490
-        }
491 481
         break;
492 482
     case TIFF_PREDICTOR:
493 483
         s->predictor = value;
... ...
@@ -517,24 +477,27 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
517 517
         }
518 518
         s->fill_order = value - 1;
519 519
         break;
520
-    case TIFF_PAL:
520
+    case TIFF_PAL: {
521
+        GetByteContext pal_gb[3];
521 522
         pal = (uint32_t *) s->palette;
522 523
         off = type_sizes[type];
523
-        if (count / 3 > 256 || end_buf - buf < count / 3 * off * 3)
524
+        if (count / 3 > 256 ||
525
+            bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3)
524 526
             return AVERROR_INVALIDDATA;
525
-        rp  = buf;
526
-        gp  = buf + count / 3 * off;
527
-        bp  = buf + count / 3 * off * 2;
527
+        pal_gb[0] = pal_gb[1] = pal_gb[2] = s->gb;
528
+        bytestream2_skip(&pal_gb[1], count / 3 * off);
529
+        bytestream2_skip(&pal_gb[2], count / 3 * off * 2);
528 530
         off = (type_sizes[type] - 1) << 3;
529 531
         for (i = 0; i < count / 3; i++) {
530 532
             uint32_t p = 0xFF000000;
531
-            p |= (tget(&rp, type, s->le) >> off) << 16;
532
-            p |= (tget(&gp, type, s->le) >> off) << 8;
533
-            p |=  tget(&bp, type, s->le) >> off;
533
+            p |= (tget(&pal_gb[0], type, s->le) >> off) << 16;
534
+            p |= (tget(&pal_gb[1], type, s->le) >> off) << 8;
535
+            p |=  tget(&pal_gb[2], type, s->le) >> off;
534 536
             pal[i] = p;
535 537
         }
536 538
         s->palette_is_set = 1;
537 539
         break;
540
+    }
538 541
     case TIFF_PLANAR:
539 542
         if (value == 2) {
540 543
             avpriv_report_missing_feature(s->avctx, "Planar format");
... ...
@@ -557,28 +520,29 @@ static int tiff_decode_tag(TiffContext *s, const uint8_t *start,
557 557
             return AVERROR_INVALIDDATA;
558 558
         }
559 559
     }
560
+    bytestream2_seek(&s->gb, start, SEEK_SET);
560 561
     return 0;
561 562
 }
562 563
 
563 564
 static int decode_frame(AVCodecContext *avctx,
564 565
                         void *data, int *got_frame, AVPacket *avpkt)
565 566
 {
566
-    const uint8_t *buf = avpkt->data;
567
-    int buf_size       = avpkt->size;
568 567
     TiffContext *const s = avctx->priv_data;
569 568
     AVFrame *const p = data;
570
-    const uint8_t *orig_buf = buf, *end_buf = buf + buf_size;
571 569
     unsigned off;
572 570
     int id, le, ret;
573 571
     int i, j, entries, stride;
574 572
     unsigned soff, ssize;
575 573
     uint8_t *dst;
574
+    GetByteContext stripsizes;
575
+    GetByteContext stripdata;
576
+
577
+    bytestream2_init(&s->gb, avpkt->data, avpkt->size);
576 578
 
577 579
     // parse image header
578
-    if (end_buf - buf < 8)
580
+    if (avpkt->size < 8)
579 581
         return AVERROR_INVALIDDATA;
580
-    id   = AV_RL16(buf);
581
-    buf += 2;
582
+    id = bytestream2_get_le16(&s->gb);
582 583
     if (id == 0x4949)
583 584
         le = 1;
584 585
     else if (id == 0x4D4D)
... ...
@@ -593,27 +557,26 @@ static int decode_frame(AVCodecContext *avctx,
593 593
     s->fill_order = 0;
594 594
     // As TIFF 6.0 specification puts it "An arbitrary but carefully chosen number
595 595
     // that further identifies the file as a TIFF file"
596
-    if (tget_short(&buf, le) != 42) {
596
+    if (tget_short(&s->gb, le) != 42) {
597 597
         av_log(avctx, AV_LOG_ERROR,
598 598
                "The answer to life, universe and everything is not correct!\n");
599 599
         return AVERROR_INVALIDDATA;
600 600
     }
601
-    // Reset these pointers so we can tell if they were set this frame
602
-    s->stripsizes = s->stripdata = NULL;
601
+    // Reset these offsets so we can tell if they were set this frame
602
+    s->stripsizesoff = s->strippos = 0;
603 603
     /* parse image file directory */
604
-    off = tget_long(&buf, le);
605
-    if (off >= UINT_MAX - 14 || end_buf - orig_buf < off + 14) {
604
+    off = tget_long(&s->gb, le);
605
+    if (off >= UINT_MAX - 14 || avpkt->size < off + 14) {
606 606
         av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
607 607
         return AVERROR_INVALIDDATA;
608 608
     }
609
-    buf     = orig_buf + off;
610
-    entries = tget_short(&buf, le);
609
+    bytestream2_seek(&s->gb, off, SEEK_SET);
610
+    entries = tget_short(&s->gb, le);
611 611
     for (i = 0; i < entries; i++) {
612
-        if ((ret = tiff_decode_tag(s, orig_buf, buf, end_buf)) < 0)
612
+        if ((ret = tiff_decode_tag(s)) < 0)
613 613
             return ret;
614
-        buf += 12;
615 614
     }
616
-    if (!s->stripdata && !s->stripoff) {
615
+    if (!s->strippos && !s->stripoff) {
617 616
         av_log(avctx, AV_LOG_ERROR, "Image data is missing\n");
618 617
         return AVERROR_INVALIDDATA;
619 618
     }
... ...
@@ -623,30 +586,40 @@ static int decode_frame(AVCodecContext *avctx,
623 623
 
624 624
     if (s->strips == 1 && !s->stripsize) {
625 625
         av_log(avctx, AV_LOG_WARNING, "Image data size missing\n");
626
-        s->stripsize = buf_size - s->stripoff;
626
+        s->stripsize = avpkt->size - s->stripoff;
627 627
     }
628 628
     stride = p->linesize[0];
629 629
     dst    = p->data[0];
630
+
631
+    if (s->stripsizesoff) {
632
+        if (s->stripsizesoff >= avpkt->size)
633
+            return AVERROR_INVALIDDATA;
634
+        bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff,
635
+                         avpkt->size - s->stripsizesoff);
636
+    }
637
+    if (s->strippos) {
638
+        if (s->strippos >= avpkt->size)
639
+            return AVERROR_INVALIDDATA;
640
+        bytestream2_init(&stripdata, avpkt->data + s->strippos,
641
+                         avpkt->size - s->strippos);
642
+    }
643
+
630 644
     for (i = 0; i < s->height; i += s->rps) {
631
-        if (s->stripsizes) {
632
-            if (s->stripsizes >= end_buf)
633
-                return AVERROR_INVALIDDATA;
634
-            ssize = tget(&s->stripsizes, s->sstype, s->le);
635
-        } else
645
+        if (s->stripsizesoff)
646
+            ssize = tget(&stripsizes, s->sstype, le);
647
+        else
636 648
             ssize = s->stripsize;
637 649
 
638
-        if (s->stripdata) {
639
-            if (s->stripdata >= end_buf)
640
-                return AVERROR_INVALIDDATA;
641
-            soff = tget(&s->stripdata, s->sot, s->le);
642
-        } else
650
+        if (s->strippos)
651
+            soff = tget(&stripdata, s->sot, le);
652
+        else
643 653
             soff = s->stripoff;
644 654
 
645
-        if (soff > buf_size || ssize > buf_size - soff) {
655
+        if (soff > avpkt->size || ssize > avpkt->size - soff) {
646 656
             av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
647 657
             return AVERROR_INVALIDDATA;
648 658
         }
649
-        if ((ret = tiff_unpack_strip(s, dst, stride, orig_buf + soff, ssize,
659
+        if ((ret = tiff_unpack_strip(s, dst, stride, avpkt->data + soff, ssize,
650 660
                                      FFMIN(s->rps, s->height - i))) < 0) {
651 661
             if (avctx->err_recognition & AV_EF_EXPLODE)
652 662
                 return ret;
... ...
@@ -675,7 +648,7 @@ static int decode_frame(AVCodecContext *avctx,
675 675
     }
676 676
     *got_frame = 1;
677 677
 
678
-    return buf_size;
678
+    return avpkt->size;
679 679
 }
680 680
 
681 681
 static av_cold int tiff_init(AVCodecContext *avctx)