diff --git a/NEWS b/NEWS index 225988ad693..be47c107c94 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,9 @@ PHP NEWS . Fixed bug GHSA-865w-9rf3-2wh5 (Logs from childrens may be altered). (CVE-2024-9026) (Jakub Zelenka) +- JSON: + . Fixed bug GH-15168 (stack overflow in json_encode()). (nielsdos) + - LDAP: . Fixed bug GH-16032 (Various NULL pointer dereferencements in ldap_modify_batch()). (Girgias) diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index de3106601b9..7c44a7f5c7a 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -32,6 +32,15 @@ static const char digits[] = "0123456789abcdef"; +static zend_always_inline bool php_json_check_stack_limit(void) +{ +#ifdef ZEND_CHECK_STACK_LIMIT + return zend_call_stack_overflowed(EG(stack_limit)); +#else + return false; +#endif +} + static int php_json_determine_array_type(zval *val) /* {{{ */ { zend_array *myht = Z_ARRVAL_P(val); @@ -117,6 +126,14 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options, HashTable *myht, *prop_ht; zend_refcounted *recursion_rc; + if (php_json_check_stack_limit()) { + encoder->error_code = PHP_JSON_ERROR_DEPTH; + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; + } + if (Z_TYPE_P(val) == IS_ARRAY) { myht = Z_ARRVAL_P(val); recursion_rc = (zend_refcounted *)myht; diff --git a/ext/json/tests/gh15168.phpt b/ext/json/tests/gh15168.phpt new file mode 100644 index 00000000000..bb17c0f7166 --- /dev/null +++ b/ext/json/tests/gh15168.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-15168 (stack overflow in json_encode()) +--SKIPIF-- + +--INI-- +zend.max_allowed_stack_size=512K +--FILE-- +next = $newNode; + $node = $newNode; +} + +var_dump(json_encode($firstNode, depth: 500000)); +var_dump(json_last_error()); +var_dump(json_last_error_msg()); + +?> +--EXPECT-- +bool(false) +int(1) +string(28) "Maximum stack depth exceeded"