Blame SOURCES/libtiff-CVE-2012-5581.patch

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