summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-09-23 13:06:55 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-09-23 13:08:44 +0200
commite65adc9c190fbaadfc9cad044ee0a3cc5df15973 (patch)
tree54d9bd85cfb0ed3a4efe9e7e46b0ca9de38064b5
parent9c89f43d55e758525c1b948915d99b5c20fd9b04 (diff)
downloadphp-git-e65adc9c190fbaadfc9cad044ee0a3cc5df15973.tar.gz
Fix ubsan violation in parse_iv2
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.
-rw-r--r--ext/standard/tests/serialize/unserialize_neg_iv_edge_cases.phpt12
-rw-r--r--ext/standard/var_unserializer.re4
2 files changed, 14 insertions, 2 deletions
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
index 0000000000..a3732bde1b
--- /dev/null
+++ b/ext/standard/tests/serialize/unserialize_neg_iv_edge_cases.phpt
@@ -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)
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index c99e673c8d..1eff008da8 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -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)