Fix unsafe handling of DotRange and related tags. Back-port of upstream
patch for CVE-2012-5581. (Note: I have not pushed this into upstream CVS
for the 3.9 branch, because I'm not entirely convinced that it won't create
application compatibility issues --- tgl)
diff -Naur tiff-3.9.4.orig/libtiff/tif_dir.c tiff-3.9.4/libtiff/tif_dir.c
--- tiff-3.9.4.orig/libtiff/tif_dir.c 2010-06-09 17:15:27.000000000 -0400
+++ tiff-3.9.4/libtiff/tif_dir.c 2012-12-10 15:12:38.442326919 -0500
@@ -492,31 +492,28 @@
goto end;
}
- if ((fip->field_passcount
+ if (fip->field_tag == TIFFTAG_DOTRANGE
+ && strcmp(fip->field_name,"DotRange") == 0) {
+ /* TODO: This is an evil exception and should not have been
+ handled this way ... likely best if we move it into
+ the directory structure with an explicit field in
+ libtiff 4.1 and assign it a FIELD_ value */
+ uint16 v[2];
+ v[0] = (uint16)va_arg(ap, int);
+ v[1] = (uint16)va_arg(ap, int);
+ _TIFFmemcpy(tv->value, v, 4);
+ }
+ else if (fip->field_passcount
|| fip->field_writecount == TIFF_VARIABLE
|| fip->field_writecount == TIFF_VARIABLE2
|| fip->field_writecount == TIFF_SPP
- || tv->count > 1)
- && fip->field_tag != TIFFTAG_PAGENUMBER
- && fip->field_tag != TIFFTAG_HALFTONEHINTS
- && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
- && fip->field_tag != TIFFTAG_DOTRANGE) {
+ || tv->count > 1) {
_TIFFmemcpy(tv->value, va_arg(ap, void *),
tv->count * tv_size);
} else {
- /*
- * XXX: The following loop required to handle
- * TIFFTAG_PAGENUMBER, TIFFTAG_HALFTONEHINTS,
- * TIFFTAG_YCBCRSUBSAMPLING and TIFFTAG_DOTRANGE tags.
- * These tags are actually arrays and should be passed as
- * array pointers to TIFFSetField() function, but actually
- * passed as a list of separate values. This behaviour
- * must be changed in the future!
- */
- int i;
char *val = (char *)tv->value;
- for (i = 0; i < tv->count; i++, val += tv_size) {
+ assert( tv->count == 1 );
switch (fip->field_type) {
case TIFF_BYTE:
case TIFF_UNDEFINED:
@@ -575,7 +572,6 @@
status = 0;
break;
}
- }
}
}
}
@@ -866,24 +862,27 @@
*va_arg(ap, uint16*) = (uint16)tv->count;
*va_arg(ap, void **) = tv->value;
ret_val = 1;
- } else {
- if ((fip->field_type == TIFF_ASCII
+ } else if (fip->field_tag == TIFFTAG_DOTRANGE
+ && strcmp(fip->field_name,"DotRange") == 0) {
+ /* TODO: This is an evil exception and should not have been
+ handled this way ... likely best if we move it into
+ the directory structure with an explicit field in
+ libtiff 4.1 and assign it a FIELD_ value */
+ *va_arg(ap, uint16*) = ((uint16 *)tv->value)[0];
+ *va_arg(ap, uint16*) = ((uint16 *)tv->value)[1];
+ ret_val = 1;
+ } else {
+ if (fip->field_type == TIFF_ASCII
|| fip->field_readcount == TIFF_VARIABLE
|| fip->field_readcount == TIFF_VARIABLE2
|| fip->field_readcount == TIFF_SPP
- || tv->count > 1)
- && fip->field_tag != TIFFTAG_PAGENUMBER
- && fip->field_tag != TIFFTAG_HALFTONEHINTS
- && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
- && fip->field_tag != TIFFTAG_DOTRANGE) {
+ || tv->count > 1) {
*va_arg(ap, void **) = tv->value;
ret_val = 1;
} else {
- int j;
char *val = (char *)tv->value;
- for (j = 0; j < tv->count;
- j++, val += _TIFFDataSize(tv->info->field_type)) {
+ assert( tv->count == 1 );
switch (fip->field_type) {
case TIFF_BYTE:
case TIFF_UNDEFINED:
@@ -933,7 +932,6 @@
ret_val = 0;
break;
}
- }
}
}
break;
diff -Naur tiff-3.9.4.orig/libtiff/tif_print.c tiff-3.9.4/libtiff/tif_print.c
--- tiff-3.9.4.orig/libtiff/tif_print.c 2010-06-08 14:50:42.000000000 -0400
+++ tiff-3.9.4/libtiff/tif_print.c 2012-12-10 15:41:42.860710914 -0500
@@ -112,16 +112,22 @@
}
static int
-_TIFFPrettyPrintField(TIFF* tif, FILE* fd, ttag_t tag,
+_TIFFPrettyPrintField(TIFF* tif, const TIFFFieldInfo *fip, FILE* fd, ttag_t tag,
uint32 value_count, void *raw_data)
{
TIFFDirectory *td = &tif->tif_dir;
+ /* do not try to pretty print auto-defined fields */
+ if (strncmp(fip->field_name,"Tag ", 4) == 0) {
+ return 0;
+ }
+
switch (tag)
{
case TIFFTAG_INKSET:
- fprintf(fd, " Ink Set: ");
- switch (*((uint16*)raw_data)) {
+ if (value_count == 2 && fip->field_type == TIFF_SHORT) {
+ fprintf(fd, " Ink Set: ");
+ switch (*((uint16*)raw_data)) {
case INKSET_CMYK:
fprintf(fd, "CMYK\n");
break;
@@ -130,15 +136,26 @@
*((uint16*)raw_data),
*((uint16*)raw_data));
break;
+ }
+ return 1;
}
- return 1;
+ return 0;
+
case TIFFTAG_DOTRANGE:
- fprintf(fd, " Dot Range: %u-%u\n",
- ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]);
- return 1;
+ if (value_count == 2 && fip->field_type == TIFF_SHORT) {
+ fprintf(fd, " Dot Range: %u-%u\n",
+ ((uint16*)raw_data)[0], ((uint16*)raw_data)[1]);
+ return 1;
+ }
+ return 0;
+
case TIFFTAG_WHITEPOINT:
- fprintf(fd, " White Point: %g-%g\n",
- ((float *)raw_data)[0], ((float *)raw_data)[1]); return 1;
+ if (value_count == 2 && fip->field_type == TIFF_RATIONAL) {
+ fprintf(fd, " White Point: %g-%g\n",
+ ((float *)raw_data)[0], ((float *)raw_data)[1]); return 1;
+ }
+ return 0;
+
case TIFFTAG_REFERENCEBLACKWHITE:
{
uint16 i;
@@ -178,10 +195,13 @@
(unsigned long) value_count);
return 1;
case TIFFTAG_STONITS:
- fprintf(fd,
- " Sample to Nits conversion factor: %.4e\n",
- *((double*)raw_data));
- return 1;
+ if (value_count == 1 && fip->field_type == TIFF_DOUBLE) {
+ fprintf(fd,
+ " Sample to Nits conversion factor: %.4e\n",
+ *((double*)raw_data));
+ return 1;
+ }
+ return 0;
}
return 0;
@@ -528,44 +548,28 @@
value_count = td->td_samplesperpixel;
else
value_count = fip->field_readcount;
- if ((fip->field_type == TIFF_ASCII
+ if (fip->field_tag == TIFFTAG_DOTRANGE
+ && strcmp(fip->field_name,"DotRange") == 0) {
+ /* TODO: This is an evil exception and should not have been
+ handled this way ... likely best if we move it into
+ the directory structure with an explicit field in
+ libtiff 4.1 and assign it a FIELD_ value */
+ static uint16 dotrange[2];
+ raw_data = dotrange;
+ TIFFGetField(tif, tag, dotrange+0, dotrange+1);
+ } else if (fip->field_type == TIFF_ASCII
|| fip->field_readcount == TIFF_VARIABLE
|| fip->field_readcount == TIFF_VARIABLE2
|| fip->field_readcount == TIFF_SPP
- || value_count > 1)
- && fip->field_tag != TIFFTAG_PAGENUMBER
- && fip->field_tag != TIFFTAG_HALFTONEHINTS
- && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
- && fip->field_tag != TIFFTAG_DOTRANGE) {
+ || value_count > 1) {
if(TIFFGetField(tif, tag, &raw_data) != 1)
continue;
- } else if (fip->field_tag != TIFFTAG_PAGENUMBER
- && fip->field_tag != TIFFTAG_HALFTONEHINTS
- && fip->field_tag != TIFFTAG_YCBCRSUBSAMPLING
- && fip->field_tag != TIFFTAG_DOTRANGE) {
- raw_data = _TIFFmalloc(
- _TIFFDataSize(fip->field_type)
- * value_count);
- mem_alloc = 1;
- if(TIFFGetField(tif, tag, raw_data) != 1) {
- _TIFFfree(raw_data);
- continue;
- }
} else {
- /*
- * XXX: Should be fixed and removed, see the
- * notes related to TIFFTAG_PAGENUMBER,
- * TIFFTAG_HALFTONEHINTS,
- * TIFFTAG_YCBCRSUBSAMPLING and
- * TIFFTAG_DOTRANGE tags in tif_dir.c. */
- char *tmp;
raw_data = _TIFFmalloc(
_TIFFDataSize(fip->field_type)
* value_count);
- tmp = raw_data;
mem_alloc = 1;
- if(TIFFGetField(tif, tag, tmp,
- tmp + _TIFFDataSize(fip->field_type)) != 1) {
+ if(TIFFGetField(tif, tag, raw_data) != 1) {
_TIFFfree(raw_data);
continue;
}
@@ -578,7 +582,7 @@
* _TIFFPrettyPrintField() fall down and print it as any other
* tag.
*/
- if (_TIFFPrettyPrintField(tif, fd, tag, value_count, raw_data)) {
+ if (_TIFFPrettyPrintField(tif, fip, fd, tag, value_count, raw_data)) {
if(mem_alloc)
_TIFFfree(raw_data);
continue;