]> granicus.if.org Git - php/commitdiff
Fix ubsan violation in parse_iv2
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 23 Sep 2019 11:06:55 +0000 (13:06 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 23 Sep 2019 11:08:44 +0000 (13:08 +0200)
This fixes two issues:
 * Negative the value in an unsigned type to avoid signed overflow.
 * Treat -0 as 0 rather than an invalid number that gets converted
   to ZEND_LONG_MIN.

ext/standard/tests/serialize/unserialize_neg_iv_edge_cases.phpt [new file with mode: 0644]
ext/standard/var_unserializer.re

diff --git a/ext/standard/tests/serialize/unserialize_neg_iv_edge_cases.phpt b/ext/standard/tests/serialize/unserialize_neg_iv_edge_cases.phpt
new file mode 100644 (file)
index 0000000..a3732bd
--- /dev/null
@@ -0,0 +1,12 @@
+--TEST--
+Negative parse_iv2 edge cases
+--FILE--
+<?php
+
+var_dump(unserialize('i:-9223372036854775808;'));
+var_dump(unserialize('i:-0;'));
+
+?>
+--EXPECT--
+int(-9223372036854775808)
+int(0)
index c99e673c8d2ea87ce5a2d1dee9b0e3d2ecce8637..1eff008da8b061f73aed2ba2fc243a8d276186c1 100644 (file)
@@ -357,12 +357,12 @@ static inline zend_long parse_iv2(const unsigned char *p, const unsigned char **
         || (SIZEOF_ZEND_LONG == 4
                && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
                && UNEXPECTED(*start > '2'))
-        || UNEXPECTED(result - neg > ZEND_LONG_MAX)) {
+        || UNEXPECTED(result > ZEND_LONG_MAX + neg)) {
                php_error_docref(NULL, E_WARNING, "Numerical result out of range");
                return (!neg) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
        }
 
-       return (!neg) ? (zend_long)result : -(zend_long)result;
+       return (zend_long) ((!neg) ? result : -result);
 }
 
 static inline zend_long parse_iv(const unsigned char *p)