From f3df3df8737ace9f4431416fdd0d312cb0ee9cfd Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 21 Jun 2015 15:30:33 +0100 Subject: [PATCH] Fix bug #68546 (json_decode cannot access property started with \0) --- NEWS | 2 ++ ext/json/json.c | 3 +++ ext/json/json_parser.tab.c | 24 +++++++++++++++++------- ext/json/json_parser.y | 18 ++++++++++++++---- ext/json/php_json.h | 1 + ext/json/tests/bug68546.phpt | 25 +++++++++++++++++++++++++ 6 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 ext/json/tests/bug68546.phpt diff --git a/NEWS b/NEWS index e5607192e0..da7583664a 100644 --- a/NEWS +++ b/NEWS @@ -199,6 +199,8 @@ PHP NEWS (JSON extension includes a problematic license statement). (Jakub Zelenka) . Fixed bug #68938 (json_decode() decodes empty string without error). (jeremy at bat-country dot us) + . Fixed bug #68546 (json_decode() Fatal error: Cannot access property + started with '\0'). (Jakub Zelenka) - LDAP . Fixed bug #47222 (Implement LDAP_OPT_DIAGNOSTIC_MESSAGE). (Andreas Heigl) diff --git a/ext/json/json.c b/ext/json/json.c index 1caef65013..8088a89b4e 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -121,6 +121,7 @@ static PHP_MINIT_FUNCTION(json) REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("JSON_ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING, CONST_CS | CONST_PERSISTENT); @@ -300,6 +301,8 @@ static PHP_FUNCTION(json_last_error_msg) RETURN_STRING("Inf and NaN cannot be JSON encoded"); case PHP_JSON_ERROR_UNSUPPORTED_TYPE: RETURN_STRING("Type is not supported"); + case PHP_JSON_ERROR_INVALID_PROPERTY_NAME: + RETURN_STRING("The decoded property name is invalid"); default: RETURN_STRING("Unknown error"); } diff --git a/ext/json/json_parser.tab.c b/ext/json/json_parser.tab.c index 45a982bbcc..052fc17137 100644 --- a/ext/json/json_parser.tab.c +++ b/ext/json/json_parser.tab.c @@ -204,7 +204,7 @@ int php_json_yyparse (php_json_parser *parser); int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); void php_json_yyerror(php_json_parser *parser, char const *msg); void php_json_parser_object_init(php_json_parser *parser, zval *object); -void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); void php_json_parser_array_init(zval *object); void php_json_parser_array_append(zval *array, zval *zvalue); @@ -515,9 +515,9 @@ static const yytype_uint8 yytranslate[] = static const yytype_uint8 yyrline[] = { 0, 92, 92, 98, 105, 105, 113, 114, 123, 126, - 130, 135, 140, 147, 152, 159, 159, 167, 168, 177, - 180, 184, 189, 194, 201, 202, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 219 + 130, 136, 142, 149, 154, 161, 161, 169, 170, 179, + 182, 186, 191, 196, 203, 204, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 221 }; #endif @@ -1499,7 +1499,8 @@ yyreduce: { php_json_parser_object_init(parser, &(yyval.value)); - php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val); + if (php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + YYERROR; } break; @@ -1507,7 +1508,8 @@ yyreduce: case 11: { - php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val); + if (php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + YYERROR; ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); } @@ -1860,7 +1862,7 @@ void php_json_parser_object_init(php_json_parser *parser, zval *object) } } -void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) { /* if JSON_OBJECT_AS_ARRAY is set */ if (Z_TYPE_P(object) == IS_ARRAY) { @@ -1870,6 +1872,12 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s if (key->len == 0) { zend_string_release(key); key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0); + } else if (key->val[0] == '\0') { + parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME; + zend_string_release(key); + zval_dtor(zvalue); + zval_dtor(object); + return FAILURE; } ZVAL_NEW_STR(&zkey, key); zend_std_write_property(object, &zkey, zvalue, NULL); @@ -1879,6 +1887,8 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s } } zend_string_release(key); + + return SUCCESS; } void php_json_parser_array_init(zval *array) diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y index 500a0ff11d..1521be69b8 100644 --- a/ext/json/json_parser.y +++ b/ext/json/json_parser.y @@ -73,7 +73,7 @@ int json_yydebug = 1; int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); void php_json_yyerror(php_json_parser *parser, char const *msg); void php_json_parser_object_init(php_json_parser *parser, zval *object); -void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); void php_json_parser_array_init(zval *object); void php_json_parser_array_append(zval *array, zval *zvalue); @@ -130,11 +130,13 @@ member: pair { php_json_parser_object_init(parser, &$$); - php_json_parser_object_update(parser, &$$, $1.key, &$1.val); + if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE) + YYERROR; } | member ',' pair { - php_json_parser_object_update(parser, &$1, $3.key, &$3.val); + if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE) + YYERROR; ZVAL_COPY_VALUE(&$$, &$1); } | member errlex @@ -248,7 +250,7 @@ void php_json_parser_object_init(php_json_parser *parser, zval *object) } } -void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) { /* if JSON_OBJECT_AS_ARRAY is set */ if (Z_TYPE_P(object) == IS_ARRAY) { @@ -258,6 +260,12 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s if (key->len == 0) { zend_string_release(key); key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0); + } else if (key->val[0] == '\0') { + parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME; + zend_string_release(key); + zval_dtor(zvalue); + zval_dtor(object); + return FAILURE; } ZVAL_NEW_STR(&zkey, key); zend_std_write_property(object, &zkey, zvalue, NULL); @@ -267,6 +275,8 @@ void php_json_parser_object_update(php_json_parser *parser, zval *object, zend_s } } zend_string_release(key); + + return SUCCESS; } void php_json_parser_array_init(zval *array) diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 54d94da498..c47bc0f401 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -51,6 +51,7 @@ typedef enum { PHP_JSON_ERROR_RECURSION, PHP_JSON_ERROR_INF_OR_NAN, PHP_JSON_ERROR_UNSUPPORTED_TYPE, + PHP_JSON_ERROR_INVALID_PROPERTY_NAME, PHP_JSON_ERROR_UTF16 } php_json_error_code; diff --git a/ext/json/tests/bug68546.phpt b/ext/json/tests/bug68546.phpt new file mode 100644 index 0000000000..f8c8d135f3 --- /dev/null +++ b/ext/json/tests/bug68546.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #68546 (json_decode() Fatal error: Cannot access property started with '\0') +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +NULL +bool(true) +NULL +bool(true) +string(36) "The decoded property name is invalid" +Done -- 2.40.0