Blob Blame History Raw
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;