]> granicus.if.org Git - php/commitdiff
Fixed bug #71534 (Type confusion in exif_read_data() leading to heap overflow in...
authorKalle Sommer Nielsen <kalle@php.net>
Sun, 7 Aug 2016 03:35:46 +0000 (05:35 +0200)
committerKalle Sommer Nielsen <kalle@php.net>
Sun, 7 Aug 2016 03:35:46 +0000 (05:35 +0200)
Unlike the original patch, this does not return an unknown format in case an unsigned compatible type cannot be found (cases for SINGLE and DOUBLE removed), as these seems rare cases according to the inline comments.

Note, the test does not test if PHP is in debug mode, although the report originally states it only occurs there only.

The fix is based on a patch by hlt99 at blinkenshell dot org

NEWS
ext/exif/exif.c
ext/exif/tests/bug71534.phpt [new file with mode: 0644]
ext/exif/tests/bug71534.tiff [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 5a63c37bff5f38d70aff16f11d249326d9e9c911..c978a6acbae1f2dea5a8e244e77cd08e603cf4a0 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@ PHP                                                                        NEWS
     Samsung, DJI, Panasonic, Sony, Pentax, Minolta & Sigma/Foveon. (Kalle)
   . Fixed bug #72682 (exif_read_data() fails to read all data for some 
     images). (Kalle)
+  . Fixed bug #71534 (Type confusion in exif_read_data() leading to heap 
+    overflow in debug mode). (hlt99 at blinkenshell dot org, Kalle)
   . Fixed bug #68547 (Exif Header component value check error). 
     (sjh21a at gmail dot com, Kalle)
   . Fixed bug #66443 (Corrupt EXIF header: maximum directory nesting level 
index d60a17db14ff8cd34901414d42db85a6c5dd67ca..54235049ea436a4d9c23b511907276cd64449291 100644 (file)
@@ -1641,6 +1641,20 @@ static double exif_convert_any_format(void *value, int format, int motorola_inte
 }
 /* }}} */
 
+/* {{{ exif_rewrite_tag_format_to_unsigned
+ * Rewrite format tag so that it specifies an unsigned type for a tag */
+static int exif_rewrite_tag_format_to_unsigned(int format)
+{
+       switch(format) {
+               case TAG_FMT_SBYTE: return TAG_FMT_BYTE;
+               case TAG_FMT_SRATIONAL: return TAG_FMT_URATIONAL;
+               case TAG_FMT_SSHORT: return TAG_FMT_USHORT;
+               case TAG_FMT_SLONG: return TAG_FMT_ULONG;
+       }
+       return format;
+}
+/* }}} */
+
 /* {{{ exif_convert_any_to_int
  * Evaluate number, be it int, rational, or float from directory. */
 static size_t exif_convert_any_to_int(void *value, int format, int motorola_intel)
@@ -3304,18 +3318,18 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
                        switch(tag) {
                                case TAG_IMAGEWIDTH:
                                case TAG_COMP_IMAGE_WIDTH:
-                                       ImageInfo->Thumbnail.width = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel);
+                                       ImageInfo->Thumbnail.width = exif_convert_any_to_int(value_ptr, exif_rewrite_tag_format_to_unsigned(format), ImageInfo->motorola_intel);
                                        break;
 
                                case TAG_IMAGEHEIGHT:
                                case TAG_COMP_IMAGE_HEIGHT:
-                                       ImageInfo->Thumbnail.height = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel);
+                                       ImageInfo->Thumbnail.height = exif_convert_any_to_int(value_ptr, exif_rewrite_tag_format_to_unsigned(format), ImageInfo->motorola_intel);
                                        break;
 
                                case TAG_STRIP_OFFSETS:
                                case TAG_JPEG_INTERCHANGE_FORMAT:
                                        /* accept both formats */
-                                       ImageInfo->Thumbnail.offset = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel);
+                                       ImageInfo->Thumbnail.offset = exif_convert_any_to_int(value_ptr, exif_rewrite_tag_format_to_unsigned(format), ImageInfo->motorola_intel);
                                        break;
 
                                case TAG_STRIP_BYTE_COUNTS:
@@ -3325,13 +3339,13 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
                                                /* motorola is easier to read */
                                                ImageInfo->Thumbnail.filetype = IMAGE_FILETYPE_TIFF_MM;
                                        }
-                                       ImageInfo->Thumbnail.size = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel);
+                                       ImageInfo->Thumbnail.size = exif_convert_any_to_int(value_ptr, exif_rewrite_tag_format_to_unsigned(format), ImageInfo->motorola_intel);
                                        break;
 
                                case TAG_JPEG_INTERCHANGE_FORMAT_LEN:
                                        if (ImageInfo->Thumbnail.filetype == IMAGE_FILETYPE_UNKNOWN) {
                                                ImageInfo->Thumbnail.filetype = IMAGE_FILETYPE_JPEG;
-                                               ImageInfo->Thumbnail.size = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel);
+                                               ImageInfo->Thumbnail.size = exif_convert_any_to_int(value_ptr, exif_rewrite_tag_format_to_unsigned(format), ImageInfo->motorola_intel);
                                        }
                                        break;
                        }
@@ -3403,7 +3417,7 @@ static int exif_process_IFD_TAG(image_info_type *ImageInfo, char *dir_entry, cha
                                break;
 
                        case TAG_COMP_IMAGE_WIDTH:
-                               ImageInfo->ExifImageWidth = exif_convert_any_to_int(value_ptr, format, ImageInfo->motorola_intel);
+                               ImageInfo->ExifImageWidth = exif_convert_any_to_int(value_ptr, exif_rewrite_tag_format_to_unsigned(format), ImageInfo->motorola_intel);
                                break;
 
                        case TAG_FOCALPLANE_X_RES:
diff --git a/ext/exif/tests/bug71534.phpt b/ext/exif/tests/bug71534.phpt
new file mode 100644 (file)
index 0000000..1f5fc9d
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+Bug #71534 (Type confusion in exif_read_data() leading to heap overflow in debug mode)
+--SKIPIF--
+<?php if (!extension_loaded('exif')) print 'skip exif extension not available';?>
+--FILE--
+<?php
+// This is kinda bad, I know! But, this generates about 200+ warnings due to its
+// broken TIFF format
+var_dump(@exif_read_data(__DIR__ . DIRECTORY_SEPARATOR . 'bug71534.tiff') === false);
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/exif/tests/bug71534.tiff b/ext/exif/tests/bug71534.tiff
new file mode 100644 (file)
index 0000000..1a224d5
Binary files /dev/null and b/ext/exif/tests/bug71534.tiff differ