diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2018-07-02 17:28:45 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2018-07-02 17:29:32 +0200 |
commit | 09bb2527e96bcefa79ae5d5d93038f2a0cc80d0a (patch) | |
tree | c19721a3c63f378a4bc66113a41188bf992ed03c /ext | |
parent | 26a33a96fa5a85bcc74e33c1b8103d3841e11bad (diff) | |
parent | c793885b7624be4e2a95c69a2b8b3fee969b312f (diff) | |
download | php-git-09bb2527e96bcefa79ae5d5d93038f2a0cc80d0a.tar.gz |
Merge branch 'PHP-7.1' into PHP-7.2
Diffstat (limited to 'ext')
-rw-r--r-- | ext/gmp/bug74670.phpt | 10 | ||||
-rw-r--r-- | ext/gmp/tests/serialize.phpt | 2 | ||||
-rw-r--r-- | ext/standard/tests/serialize/bug71311.phpt | 2 | ||||
-rw-r--r-- | ext/standard/tests/serialize/bug73341.phpt | 4 | ||||
-rw-r--r-- | ext/standard/var_unserializer.c | 74 | ||||
-rw-r--r-- | ext/standard/var_unserializer.re | 12 |
6 files changed, 63 insertions, 41 deletions
diff --git a/ext/gmp/bug74670.phpt b/ext/gmp/bug74670.phpt new file mode 100644 index 0000000000..a28640b5c6 --- /dev/null +++ b/ext/gmp/bug74670.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #74670: Integer Underflow when unserializing GMP and possible other classes +--FILE-- +<?php +$str = 'C:3:"GMP":4:{s:6666666666:""}'; +var_dump(unserialize($str)); +?> +--EXPECTF-- +Notice: unserialize(): Error at offset 13 of 29 bytes in %s on line %d +bool(false) diff --git a/ext/gmp/tests/serialize.phpt b/ext/gmp/tests/serialize.phpt index 5e308fa14e..e9b9bb549f 100644 --- a/ext/gmp/tests/serialize.phpt +++ b/ext/gmp/tests/serialize.phpt @@ -18,7 +18,7 @@ try { } catch (Exception $e) { var_dump($e->getMessage()); } try { - unserialize('C:3:"GMP":8:{s:2:"42";}'); + unserialize('C:3:"GMP":9:{s:2:"42";}'); } catch (Exception $e) { var_dump($e->getMessage()); } ?> diff --git a/ext/standard/tests/serialize/bug71311.phpt b/ext/standard/tests/serialize/bug71311.phpt index 3c70783d37..70267c5b0b 100644 --- a/ext/standard/tests/serialize/bug71311.phpt +++ b/ext/standard/tests/serialize/bug71311.phpt @@ -2,7 +2,7 @@ Bug #71311 Use-after-free vulnerability in SPL(ArrayObject, unserialize) --FILE-- <?php -$data = unserialize("C:11:\"ArrayObject\":11:{x:i:0;r:3;XX"); +$data = unserialize("C:11:\"ArrayObject\":11:{x:i:0;r:3;X}"); var_dump($data); ?> --EXPECTF-- diff --git a/ext/standard/tests/serialize/bug73341.phpt b/ext/standard/tests/serialize/bug73341.phpt index 55423217c3..86fd457c60 100644 --- a/ext/standard/tests/serialize/bug73341.phpt +++ b/ext/standard/tests/serialize/bug73341.phpt @@ -3,7 +3,7 @@ Bug #73144 (Use-afte-free in ArrayObject Deserialization) --FILE-- <?php try { -$token = 'a:2:{i:0;O:1:"0":2:0s:1:"0";i:0;s:1:"0";a:1:{i:0;C:11:"ArrayObject":7:0x:i:0;r0'; +$token = 'a:2:{i:0;O:1:"0":2:0s:1:"0";i:0;s:1:"0";a:1:{i:0;C:11:"ArrayObject":7:{x:i:0;r}'; $obj = unserialize($token); } catch(Exception $e) { echo $e->getMessage()."\n"; @@ -21,4 +21,4 @@ unserialize($exploit); Error at offset 6 of 7 bytes Notice: ArrayObject::unserialize(): Unexpected end of serialized data in %sbug73341.php on line %d -Error at offset 24 of 34 bytes
\ No newline at end of file +Error at offset 24 of 34 bytes diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 108887580f..8c16a555fd 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.16 */ +/* Generated by re2c 1.0.1 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -519,6 +519,13 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return 0; } + /* Check that '}' is present before calling ce->unserialize() to mitigate issues + * with unserialize reading past the end of the passed buffer if the string is not + * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */ + if ((*p)[datalen] != '}') { + return 0; + } + if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name)); object_init_ex(rval, ce); @@ -526,9 +533,8 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return 0; } - (*p) += datalen; - - return finish_nested_data(UNSERIALIZE_PASSTHRU); + (*p) += datalen + 1; /* +1 for '}' */ + return 1; } static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) @@ -645,7 +651,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) start = cursor; -#line 649 "ext/standard/var_unserializer.c" +#line 655 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -703,9 +709,9 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) yy2: ++YYCURSOR; yy3: -#line 1036 "ext/standard/var_unserializer.re" +#line 1042 "ext/standard/var_unserializer.re" { return 0; } -#line 709 "ext/standard/var_unserializer.c" +#line 715 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy17; @@ -752,13 +758,13 @@ yy14: goto yy3; yy15: ++YYCURSOR; -#line 1030 "ext/standard/var_unserializer.re" +#line 1036 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 762 "ext/standard/var_unserializer.c" +#line 768 "ext/standard/var_unserializer.c" yy17: yych = *++YYCURSOR; if (yybm[0+yych] & 128) { @@ -769,13 +775,13 @@ yy18: goto yy3; yy19: ++YYCURSOR; -#line 702 "ext/standard/var_unserializer.re" +#line 708 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_NULL(rval); return 1; } -#line 779 "ext/standard/var_unserializer.c" +#line 785 "ext/standard/var_unserializer.c" yy21: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -974,7 +980,7 @@ yy55: goto yy18; yy56: ++YYCURSOR; -#line 653 "ext/standard/var_unserializer.re" +#line 659 "ext/standard/var_unserializer.re" { zend_long id; @@ -999,7 +1005,7 @@ yy56: return 1; } -#line 1003 "ext/standard/var_unserializer.c" +#line 1009 "ext/standard/var_unserializer.c" yy58: yych = *++YYCURSOR; if (yych == '"') goto yy77; @@ -1010,13 +1016,13 @@ yy59: goto yy18; yy60: ++YYCURSOR; -#line 708 "ext/standard/var_unserializer.re" +#line 714 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_BOOL(rval, parse_iv(start + 2)); return 1; } -#line 1020 "ext/standard/var_unserializer.c" +#line 1026 "ext/standard/var_unserializer.c" yy62: ++YYCURSOR; if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); @@ -1036,7 +1042,7 @@ yy62: } yy64: ++YYCURSOR; -#line 756 "ext/standard/var_unserializer.re" +#line 762 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 use_double: @@ -1045,7 +1051,7 @@ use_double: ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1049 "ext/standard/var_unserializer.c" +#line 1055 "ext/standard/var_unserializer.c" yy66: yych = *++YYCURSOR; if (yych <= ',') { @@ -1067,7 +1073,7 @@ yy68: goto yy18; yy69: ++YYCURSOR; -#line 714 "ext/standard/var_unserializer.re" +#line 720 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1093,14 +1099,14 @@ yy69: ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1097 "ext/standard/var_unserializer.c" +#line 1103 "ext/standard/var_unserializer.c" yy71: yych = *++YYCURSOR; if (yych == '"') goto yy85; goto yy18; yy72: ++YYCURSOR; -#line 678 "ext/standard/var_unserializer.re" +#line 684 "ext/standard/var_unserializer.re" { zend_long id; @@ -1124,14 +1130,14 @@ yy72: return 1; } -#line 1128 "ext/standard/var_unserializer.c" +#line 1134 "ext/standard/var_unserializer.c" yy74: yych = *++YYCURSOR; if (yych == '"') goto yy87; goto yy18; yy75: ++YYCURSOR; -#line 878 "ext/standard/var_unserializer.re" +#line 884 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; zend_long elements; @@ -1283,10 +1289,10 @@ yy75: return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 1287 "ext/standard/var_unserializer.c" +#line 1293 "ext/standard/var_unserializer.c" yy77: ++YYCURSOR; -#line 803 "ext/standard/var_unserializer.re" +#line 809 "ext/standard/var_unserializer.re" { size_t len, maxlen; zend_string *str; @@ -1320,10 +1326,10 @@ yy77: ZVAL_STR(rval, str); return 1; } -#line 1324 "ext/standard/var_unserializer.c" +#line 1330 "ext/standard/var_unserializer.c" yy79: ++YYCURSOR; -#line 837 "ext/standard/var_unserializer.re" +#line 843 "ext/standard/var_unserializer.re" { zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -1353,7 +1359,7 @@ yy79: return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 1357 "ext/standard/var_unserializer.c" +#line 1363 "ext/standard/var_unserializer.c" yy81: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1372,7 +1378,7 @@ yy84: goto yy18; yy85: ++YYCURSOR; -#line 867 "ext/standard/var_unserializer.re" +#line 873 "ext/standard/var_unserializer.re" { zend_long elements; if (!var_hash) return 0; @@ -1383,10 +1389,10 @@ yy85: } return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 1387 "ext/standard/var_unserializer.c" +#line 1393 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 765 "ext/standard/var_unserializer.re" +#line 771 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -1424,10 +1430,10 @@ yy87: } return 1; } -#line 1428 "ext/standard/var_unserializer.c" +#line 1434 "ext/standard/var_unserializer.c" yy89: ++YYCURSOR; -#line 740 "ext/standard/var_unserializer.re" +#line 746 "ext/standard/var_unserializer.re" { *p = YYCURSOR; @@ -1443,9 +1449,9 @@ yy89: return 1; } -#line 1447 "ext/standard/var_unserializer.c" +#line 1453 "ext/standard/var_unserializer.c" } -#line 1038 "ext/standard/var_unserializer.re" +#line 1044 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index af42222677..3d23925657 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -523,6 +523,13 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return 0; } + /* Check that '}' is present before calling ce->unserialize() to mitigate issues + * with unserialize reading past the end of the passed buffer if the string is not + * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */ + if ((*p)[datalen] != '}') { + return 0; + } + if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name)); object_init_ex(rval, ce); @@ -530,9 +537,8 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return 0; } - (*p) += datalen; - - return finish_nested_data(UNSERIALIZE_PASSTHRU); + (*p) += datalen + 1; /* +1 for '}' */ + return 1; } static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) |