2006.03.10 16:06 "[Tiff] LibTIFF 3.8.0 crash bug (patch included)", by Holger Schemel

2006.03.10 16:06 "[Tiff] LibTIFF 3.8.0 crash bug (patch included)", by Holger Schemel

Hello,

I have encountered a TIFF file that crashes the current stable version 3.8.0 of LibTIFF; as this TIFF file is rather large (about 10 MB), I haven't attached it to this mail, but you can get it at "http://artsoft.org/stuff/this_crashes_libtiff.tif".

For example, a simple "identify this_crashes_libtiff.tif" with ImageMagick crashes in LibTIFF, as shown by a "gdb" backtrace.

The reason for this crash on this particular image file is the following LibTIFF change (from the "ChangeLog" in version 3.8.0):

----- snip -----
2005-12-24 Andrey Kiselev <dron@remotesensing.org>

        * libtiff/{tif_aux.c, tif_dir.c, tif_dir.h, tif_dirwrite.c,

        tif_print.c, tif_getimage.c}: Make InkSet, NumberOfInks, DotRange and
        StoNits tags custom.
----- snip -----

So when using ImageMagick with LibTIFF 3.7.4, everything works just fine.

After diving a bit into the LibTIFF code, the reason for this crash seems to be the following: While the tags "InkSet", "NumberOfInks" and "StoNits" are defined to be one single data of the type TIFF_SHORT or TIFF_DOUBLE, "DotRange" are two data values of the type TIFF_BYTE or TIFF_SHORT, which are put onto the stack as two separate values in "_TIFFVSetField()" in the source file "libtiff/tif_dir.c". When falling through to the "default:" switch label, the code reaches the following part (around line 480):

----- snip -----
                if (fip->field_passcount

                    || fip->field_writecount == TIFF_VARIABLE
                    || fip->field_writecount == TIFF_VARIABLE2
                    || fip->field_writecount == TIFF_SPP
                    || tv->count > 1) {
                    _TIFFmemcpy(tv->value, va_arg(ap, void *),

                                tv->count * tv_size);
----- snip -----

The problem here is "tv->count > 1", which is true here because tv->count is "2", but there's no pointer on the stack, but two 8 or 16 bit values (which are furthermore propagated to "int").

So LibTIFF crashes in "_TIFFmemcpy()". :-(

(All other custom tags mentioned above that were removed in favor of the more generic code above are handled correctly, because their "field_writecount" is always "1" according to "tiffFieldInfo[]", so the code reaches the switch statement directly after the above code segment. But I'm not sure if it may also crash for the other custom tags that were handled explicitly in version 3.7.4 and that have more than one "simple" data value (SHORT etc.), like "TIFFTAG_DNGVERSION" or others.)

The attached very small patch is nothing else than the behaviour of the previous version 3.7.4, just put back into 3.8.0 again.

With this little change, processing the above TIFF image works just fine! :-)

Best regards,
                Holger
--
holger.schemel@artsoft.org

diff -r -c tiff-3.8.0.orig/libtiff/tif_dir.c tiff-3.8.0.fixed/libtiff/tif_dir.c

*** tiff-3.8.0.orig/libtiff/tif_dir.c   2005-12-29 22:46:38.000000000 +0100
--- tiff-3.8.0.fixed/libtiff/tif_dir.c  2006-03-03 14:33:41.000000000 +0100

***************
*** 363,368 ****
--- 363,373 ----
                        _TIFFsetShortArray(&td->td_transferfunction[i],
                            va_arg(ap, uint16*), 1L<<td->td_bitspersample);
                break;
+ case TIFFTAG_DOTRANGE:

+               /* XXX should check for null range */
+               td->td_dotrange[0] = (uint16) va_arg(ap, int);
+               td->td_dotrange[1] = (uint16) va_arg(ap, int);
+               break;

        case TIFFTAG_INKNAMES:
                v = va_arg(ap, uint32);
                s = va_arg(ap, char*);
***************
*** 777,782 ****
--- 782,791 ----

                  *va_arg(ap, uint16**) = td->td_transferfunction[2];

              }
              break;

+       case TIFFTAG_DOTRANGE:
+             *va_arg(ap, uint16*) = td->td_dotrange[0];
+             *va_arg(ap, uint16*) = td->td_dotrange[1];
+             break;
        case TIFFTAG_INKNAMES:
              *va_arg(ap, char**) = td->td_inknames;

              break;

diff -r -c tiff-3.8.0.orig/libtiff/tif_dir.h tiff-3.8.0.fixed/libtiff/tif_dir.h

*** tiff-3.8.0.orig/libtiff/tif_dir.h   2005-12-29 22:46:38.000000000 +0100
--- tiff-3.8.0.fixed/libtiff/tif_dir.h  2006-03-03 14:33:45.000000000 +0100

***************
*** 74,79 ****
--- 74,80 ----

        /* Colorimetry parameters */

        uint16* td_transferfunction[3];
        /* CMYK parameters */
+       uint16  td_dotrange[2];
        int     td_inknameslen;
        char*   td_inknames;