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