diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-09-23 13:06:55 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-09-23 13:08:44 +0200 |
commit | e65adc9c190fbaadfc9cad044ee0a3cc5df15973 (patch) | |
tree | 54d9bd85cfb0ed3a4efe9e7e46b0ca9de38064b5 | |
parent | 9c89f43d55e758525c1b948915d99b5c20fd9b04 (diff) | |
download | php-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.phpt | 12 | ||||
-rw-r--r-- | ext/standard/var_unserializer.re | 4 |
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) |