]> granicus.if.org Git - php/commitdiff
Avoid float to int cast UB in exif
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 17 Dec 2019 12:15:01 +0000 (13:15 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 17 Dec 2019 12:26:05 +0000 (13:26 +0100)
ext/exif/exif.c
ext/exif/tests/float_cast_overflow.phpt [new file with mode: 0644]
ext/exif/tests/float_cast_overflow.tiff [new file with mode: 0644]

index b686ec2fd4fae2beba772d52033d3e88a3e87902..4f8b8af719194957cd3d3e6b773e055d512b7486 100644 (file)
@@ -1697,6 +1697,27 @@ static int exif_rewrite_tag_format_to_unsigned(int format)
 }
 /* }}} */
 
+/* Use saturation for out of bounds values to avoid UB */
+static size_t float_to_size_t(float x) {
+       if (x < 0.0f) {
+               return 0;
+       } else if (x > (float) SIZE_MAX) {
+               return SIZE_MAX;
+       } else {
+               return (size_t) x;
+       }
+}
+
+static size_t double_to_size_t(double x) {
+       if (x < 0.0) {
+               return 0;
+       } else if (x > (double) SIZE_MAX) {
+               return SIZE_MAX;
+       } else {
+               return (size_t) x;
+       }
+}
+
 /* {{{ 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)
@@ -1735,12 +1756,12 @@ static size_t exif_convert_any_to_int(void *value, int format, int motorola_inte
 #ifdef EXIF_DEBUG
                        php_error_docref(NULL, E_NOTICE, "Found value of type single");
 #endif
-                       return (size_t) php_ifd_get_float(value);
+                       return float_to_size_t(php_ifd_get_float(value));
                case TAG_FMT_DOUBLE:
 #ifdef EXIF_DEBUG
                        php_error_docref(NULL, E_NOTICE, "Found value of type double");
 #endif
-                       return (size_t) php_ifd_get_double(value);
+                       return double_to_size_t(php_ifd_get_double(value));
        }
        return 0;
 }
diff --git a/ext/exif/tests/float_cast_overflow.phpt b/ext/exif/tests/float_cast_overflow.phpt
new file mode 100644 (file)
index 0000000..1121914
--- /dev/null
@@ -0,0 +1,43 @@
+--TEST--
+Overflow in float to int cast
+--FILE--
+<?php
+
+var_dump(@exif_read_data(__DIR__ . '/float_cast_overflow.tiff'));
+
+?>
+--EXPECTF--
+array(8) {
+  ["FileName"]=>
+  string(24) "float_cast_overflow.tiff"
+  ["FileDateTime"]=>
+  int(%d)
+  ["FileSize"]=>
+  int(142)
+  ["FileType"]=>
+  int(7)
+  ["MimeType"]=>
+  string(10) "image/tiff"
+  ["SectionsFound"]=>
+  string(24) "ANY_TAG, IFD0, THUMBNAIL"
+  ["COMPUTED"]=>
+  array(5) {
+    ["html"]=>
+    string(20) "width="1" height="1""
+    ["Height"]=>
+    int(1)
+    ["Width"]=>
+    int(1)
+    ["IsColor"]=>
+    int(0)
+    ["ByteOrderMotorola"]=>
+    int(0)
+  }
+  ["THUMBNAIL"]=>
+  array(2) {
+    ["ImageWidth"]=>
+    int(1)
+    ["ImageLength"]=>
+    float(-2.5961487387524E+33)
+  }
+}
diff --git a/ext/exif/tests/float_cast_overflow.tiff b/ext/exif/tests/float_cast_overflow.tiff
new file mode 100644 (file)
index 0000000..faebc8e
Binary files /dev/null and b/ext/exif/tests/float_cast_overflow.tiff differ