diff options
author | Anatol Belski <ab@php.net> | 2017-07-04 10:42:48 +0200 |
---|---|---|
committer | Joe Watkins <krakjoe@php.net> | 2017-07-04 20:07:00 +0100 |
commit | 2c567eae283308bbc1cb9836546b8dbf0146932c (patch) | |
tree | d38ecb3e814bf0ef4c4df474dd0ffdd166a14d2d | |
parent | 3d7b2117e0cf2b0f76fcdd8080d4d5c82d0f82f8 (diff) | |
download | php-git-2c567eae283308bbc1cb9836546b8dbf0146932c.tar.gz |
Merge branch 'PHP-7.0' into PHP-7.1
* PHP-7.0:
Fixed bug #74101 and bug #74614
-rw-r--r-- | ext/standard/tests/serialize/bug74101.phpt | 10 | ||||
-rw-r--r-- | ext/standard/tests/serialize/bug74614.phpt | 10 | ||||
-rw-r--r-- | ext/standard/var_unserializer.c | 68 | ||||
-rw-r--r-- | ext/standard/var_unserializer.re | 8 |
4 files changed, 62 insertions, 34 deletions
diff --git a/ext/standard/tests/serialize/bug74101.phpt b/ext/standard/tests/serialize/bug74101.phpt new file mode 100644 index 0000000000..a414060f5c --- /dev/null +++ b/ext/standard/tests/serialize/bug74101.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #74101: Unserialize Heap Use-After-Free (READ: 1) in zval_get_type +--FILE-- +<?php +$s = 'O:9:"Exception":799999999999999999999999999997:0i:0;a:0:{}i:2;i:0;i:0;R:2;'; +var_dump(unserialize($s)); +?> +--EXPECTF-- +Notice: unserialize(): Error at offset 48 of 74 bytes in %s on line %d +bool(false) diff --git a/ext/standard/tests/serialize/bug74614.phpt b/ext/standard/tests/serialize/bug74614.phpt new file mode 100644 index 0000000000..ae962628e9 --- /dev/null +++ b/ext/standard/tests/serialize/bug74614.phpt @@ -0,0 +1,10 @@ +--TEST-- +Bug #74614: Use-after-free in PHP7's unserialize() +--FILE-- +<?php + +unserialize('a:3020000000000000000000000000000001:{i:0;a:0:{}i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;i:5;i:6;i:6;i:7;i:7;i:8;i:8;R:2;}'); + +?> +--EXPECTF-- +Notice: unserialize(): Error at offset 38 of 113 bytes in %s on line %d diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 609ed45bd1..ac024fdf42 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -548,6 +548,10 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1); ht = Z_OBJPROP_P(rval); + if (elements >= HT_MAX_SIZE - zend_hash_num_elements(ht)) { + return 0; + } + zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED)); if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) { if (has_wakeup) { @@ -617,7 +621,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) start = cursor; -#line 621 "ext/standard/var_unserializer.c" +#line 625 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -675,9 +679,9 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) yy2: ++YYCURSOR; yy3: -#line 998 "ext/standard/var_unserializer.re" +#line 1002 "ext/standard/var_unserializer.re" { return 0; } -#line 681 "ext/standard/var_unserializer.c" +#line 685 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy17; @@ -724,13 +728,13 @@ yy14: goto yy3; yy15: ++YYCURSOR; -#line 992 "ext/standard/var_unserializer.re" +#line 996 "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 734 "ext/standard/var_unserializer.c" +#line 738 "ext/standard/var_unserializer.c" yy17: yych = *++YYCURSOR; if (yybm[0+yych] & 128) { @@ -742,13 +746,13 @@ yy18: goto yy3; yy19: ++YYCURSOR; -#line 676 "ext/standard/var_unserializer.re" +#line 680 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_NULL(rval); return 1; } -#line 752 "ext/standard/var_unserializer.c" +#line 756 "ext/standard/var_unserializer.c" yy21: yych = *++YYCURSOR; if (yych <= ',') { @@ -998,7 +1002,7 @@ yy62: goto yy18; yy63: ++YYCURSOR; -#line 625 "ext/standard/var_unserializer.re" +#line 629 "ext/standard/var_unserializer.re" { zend_long id; @@ -1024,7 +1028,7 @@ yy63: return 1; } -#line 1028 "ext/standard/var_unserializer.c" +#line 1032 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych == '"') goto yy84; @@ -1035,13 +1039,13 @@ yy66: goto yy18; yy67: ++YYCURSOR; -#line 682 "ext/standard/var_unserializer.re" +#line 686 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_BOOL(rval, parse_iv(start + 2)); return 1; } -#line 1045 "ext/standard/var_unserializer.c" +#line 1049 "ext/standard/var_unserializer.c" yy69: ++YYCURSOR; if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4); @@ -1061,7 +1065,7 @@ yy69: } yy71: ++YYCURSOR; -#line 730 "ext/standard/var_unserializer.re" +#line 734 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 use_double: @@ -1070,7 +1074,7 @@ use_double: ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1074 "ext/standard/var_unserializer.c" +#line 1078 "ext/standard/var_unserializer.c" yy73: yych = *++YYCURSOR; if (yych <= ',') { @@ -1092,7 +1096,7 @@ yy75: goto yy18; yy76: ++YYCURSOR; -#line 688 "ext/standard/var_unserializer.re" +#line 692 "ext/standard/var_unserializer.re" { #if SIZEOF_ZEND_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1118,14 +1122,14 @@ yy76: ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1122 "ext/standard/var_unserializer.c" +#line 1126 "ext/standard/var_unserializer.c" yy78: yych = *++YYCURSOR; if (yych == '"') goto yy92; goto yy18; yy79: ++YYCURSOR; -#line 651 "ext/standard/var_unserializer.re" +#line 655 "ext/standard/var_unserializer.re" { zend_long id; @@ -1150,14 +1154,14 @@ yy79: return 1; } -#line 1154 "ext/standard/var_unserializer.c" +#line 1158 "ext/standard/var_unserializer.c" yy81: yych = *++YYCURSOR; if (yych == '"') goto yy94; goto yy18; yy82: ++YYCURSOR; -#line 840 "ext/standard/var_unserializer.re" +#line 844 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; zend_long elements; @@ -1309,10 +1313,10 @@ yy82: return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 1313 "ext/standard/var_unserializer.c" +#line 1317 "ext/standard/var_unserializer.c" yy84: ++YYCURSOR; -#line 771 "ext/standard/var_unserializer.re" +#line 775 "ext/standard/var_unserializer.re" { size_t len, maxlen; zend_string *str; @@ -1346,17 +1350,17 @@ yy84: ZVAL_STR(rval, str); return 1; } -#line 1350 "ext/standard/var_unserializer.c" +#line 1354 "ext/standard/var_unserializer.c" yy86: ++YYCURSOR; -#line 805 "ext/standard/var_unserializer.re" +#line 809 "ext/standard/var_unserializer.re" { zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ *p = YYCURSOR; if (!var_hash) return 0; - if (elements < 0) { + if (elements < 0 || elements >= HT_MAX_SIZE) { return 0; } @@ -1373,7 +1377,7 @@ yy86: return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 1377 "ext/standard/var_unserializer.c" +#line 1381 "ext/standard/var_unserializer.c" yy88: yych = *++YYCURSOR; if (yych <= ',') { @@ -1398,21 +1402,21 @@ yy91: goto yy18; yy92: ++YYCURSOR; -#line 829 "ext/standard/var_unserializer.re" +#line 833 "ext/standard/var_unserializer.re" { long elements; if (!var_hash) return 0; elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR); - if (elements < 0) { + if (elements < 0 || elements >= HT_MAX_SIZE) { return 0; } return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 1413 "ext/standard/var_unserializer.c" +#line 1417 "ext/standard/var_unserializer.c" yy94: ++YYCURSOR; -#line 739 "ext/standard/var_unserializer.re" +#line 743 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -1444,7 +1448,7 @@ yy94: ZVAL_STRINGL(rval, str, len); return 1; } -#line 1448 "ext/standard/var_unserializer.c" +#line 1452 "ext/standard/var_unserializer.c" yy96: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1452,7 +1456,7 @@ yy96: goto yy18; yy97: ++YYCURSOR; -#line 714 "ext/standard/var_unserializer.re" +#line 718 "ext/standard/var_unserializer.re" { *p = YYCURSOR; @@ -1468,9 +1472,9 @@ yy97: return 1; } -#line 1472 "ext/standard/var_unserializer.c" +#line 1476 "ext/standard/var_unserializer.c" } -#line 1000 "ext/standard/var_unserializer.re" +#line 1004 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 8906c353b3..2b32e6b977 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -552,6 +552,10 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1); ht = Z_OBJPROP_P(rval); + if (elements >= HT_MAX_SIZE - zend_hash_num_elements(ht)) { + return 0; + } + zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED)); if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) { if (has_wakeup) { @@ -808,7 +812,7 @@ use_double: *p = YYCURSOR; if (!var_hash) return 0; - if (elements < 0) { + if (elements < 0 || elements >= HT_MAX_SIZE) { return 0; } @@ -831,7 +835,7 @@ use_double: if (!var_hash) return 0; elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR); - if (elements < 0) { + if (elements < 0 || elements >= HT_MAX_SIZE) { return 0; } return object_common2(UNSERIALIZE_PASSTHRU, elements); |