From 945b9e9e144d23f95633c72a6fcc85346feb9faa Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Tue, 19 May 2026 23:07:25 +0800 Subject: [PATCH 1/3] PHP-8.4 is now for PHP 8.4.23-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index ce2b34730978..0dbb0062c63a 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.4.22 +?? ??? ????, PHP 8.4.23 + + +04 Jun 2026, PHP 8.4.22 - Date: . Fixed bug GH-18422 (int overflow in php_date_llabs). (iliaal) diff --git a/Zend/zend.h b/Zend/zend.h index fd624675e7b6..a5d204dbdb20 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.4.22-dev" +#define ZEND_VERSION "4.4.23-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index fcc66c48858f..d6d6ecb52ac4 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.4.22-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.4.23-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index d4530cf0a3dd..1789f9cad8a4 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 4 -#define PHP_RELEASE_VERSION 22 +#define PHP_RELEASE_VERSION 23 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.4.22-dev" -#define PHP_VERSION_ID 80422 +#define PHP_VERSION "8.4.23-dev" +#define PHP_VERSION_ID 80423 From a846c8f4141ead34ee47bcf3307acc910fe91486 Mon Sep 17 00:00:00 2001 From: Volker Dusch Date: Tue, 19 May 2026 19:09:48 +0200 Subject: [PATCH 2/3] PHP-8.5 is now for PHP 8.5.8-dev --- NEWS | 5 ++++- Zend/zend.h | 2 +- configure.ac | 2 +- main/php_version.h | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index dd6e4b2d87e5..ace3e868e659 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| -?? ??? ????, PHP 8.5.7 +?? ??? ????, PHP 8.5.8 + + +02 Jun 2026, PHP 8.5.7 - CLI: . Fixed bug GH-21901 (Stale getopt() optional value). (onthebed) diff --git a/Zend/zend.h b/Zend/zend.h index 3b00d9ce4b99..b3e485dc3996 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -20,7 +20,7 @@ #ifndef ZEND_H #define ZEND_H -#define ZEND_VERSION "4.5.7-dev" +#define ZEND_VERSION "4.5.8-dev" #define ZEND_ENGINE_3 diff --git a/configure.ac b/configure.ac index eca5bcf5a0e6..4aa73071e9d2 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice. dnl ---------------------------------------------------------------------------- AC_PREREQ([2.68]) -AC_INIT([PHP],[8.5.7-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) +AC_INIT([PHP],[8.5.8-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net]) AC_CONFIG_SRCDIR([main/php_version.h]) AC_CONFIG_AUX_DIR([build]) AC_PRESERVE_HELP_ORDER diff --git a/main/php_version.h b/main/php_version.h index df9ac7aa74b8..2235b260caef 100644 --- a/main/php_version.h +++ b/main/php_version.h @@ -2,7 +2,7 @@ /* edit configure.ac to change version number */ #define PHP_MAJOR_VERSION 8 #define PHP_MINOR_VERSION 5 -#define PHP_RELEASE_VERSION 7 +#define PHP_RELEASE_VERSION 8 #define PHP_EXTRA_VERSION "-dev" -#define PHP_VERSION "8.5.7-dev" -#define PHP_VERSION_ID 80507 +#define PHP_VERSION "8.5.8-dev" +#define PHP_VERSION_ID 80508 From f5db09db144fbd65b0f56327c84ed3aa6a4f5ee2 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Sat, 9 May 2026 14:29:52 +0800 Subject: [PATCH 3/3] ext/soap: Fix integer overflow when decoding SOAP array indexes close GH-21963 --- NEWS | 3 + ext/soap/php_encoding.c | 38 +++++--- ext/soap/php_packet_soap.c | 40 +++++++-- ext/soap/soap.c | 24 ++++- ext/soap/tests/soap_array_index_overflow.phpt | 89 +++++++++++++++++++ 5 files changed, 171 insertions(+), 23 deletions(-) create mode 100644 ext/soap/tests/soap_array_index_overflow.phpt diff --git a/NEWS b/NEWS index 0dbb0062c63a..80567e1ff2b8 100644 --- a/NEWS +++ b/NEWS @@ -31,6 +31,9 @@ PHP NEWS - OpenSSL: . Fix compatibility issues with OpenSSL 4.0. (jordikroon, Remi) +- SOAP: + . Fixed integer overflow when decoding SOAP array indexes. (Weilin Du) + - SPL: . Fix SplFixedArray::setSize leak when destructor grows during clear. (David Carlier) diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index d635fff0ccaa..4eedbffc5a4b 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -16,6 +16,7 @@ +----------------------------------------------------------------------+ */ +#include #include #include "php_soap.h" @@ -2075,6 +2076,15 @@ static int calc_dimension_12(const char* str) return i; } +static void soap_array_position_add_digit(int *position, int digit) +{ + if (*position > (INT_MAX - digit) / 10) { + soap_error0(E_ERROR, "Encoding: array index out of range"); + } + + *position = (*position * 10) + digit; +} + static int* get_position_12(int dimension, const char* str) { int *pos; @@ -2095,7 +2105,7 @@ static int* get_position_12(int dimension, const char* str) i++; flag = 1; } - pos[i] = (pos[i]*10)+(*str-'0'); + soap_array_position_add_digit(&pos[i], *str - '0'); } else if (*str == '*') { soap_error0(E_ERROR, "Encoding: '*' may only be first arraySize value in list"); } else { @@ -2125,7 +2135,7 @@ static void get_position_ex(int dimension, const char* str, int** pos) memset(*pos,0,sizeof(int)*dimension); while (*str != ']' && *str != '\0' && i < dimension) { if (*str >= '0' && *str <= '9') { - (*pos)[i] = ((*pos)[i]*10)+(*str-'0'); + soap_array_position_add_digit(&(*pos)[i], *str - '0'); } else if (*str == ',') { i++; } @@ -2698,16 +2708,20 @@ static zval *to_zval_array(zval *ret, encodeTypePtr type, xmlNodePtr data) /* Increment position */ i = dimension; while (i > 0) { - i--; - pos[i]++; - if (pos[i] >= dims[i]) { - if (i > 0) { - pos[i] = 0; - } else { - /* TODO: Array index overflow */ - } - } else { - break; + i--; + if (pos[i] == INT_MAX) { + efree(dims); + efree(pos); + zval_ptr_dtor(ret); + ZVAL_UNDEF(ret); + soap_error0(E_ERROR, "Encoding: array index out of range"); + } + pos[i]++; + if (pos[i] < dims[i]) { + break; + } + if (i > 0) { + pos[i] = 0; } } } diff --git a/ext/soap/php_packet_soap.c b/ext/soap/php_packet_soap.c index fddb6b63874d..7dcd56f34cce 100644 --- a/ext/soap/php_packet_soap.c +++ b/ext/soap/php_packet_soap.c @@ -18,6 +18,28 @@ #include "php_soap.h" +static void master_to_zval_with_doc_cleanup(zval *ret, encodePtr encode, xmlNodePtr data, xmlDocPtr doc) +{ + bool bailout = false; + + ZVAL_UNDEF(ret); + + /* SoapClient can turn decode errors into a bailout before parse_packet_soap() frees the response doc. */ + zend_try { + master_to_zval(ret, encode, data); + } zend_catch { + bailout = true; + } zend_end_try(); + + if (bailout) { + if (!Z_ISUNDEF_P(ret)) { + zval_ptr_dtor(ret); + } + xmlFreeDoc(doc); + zend_bailout(); + } +} + /* SOAP client calls this function to parse response from SOAP server */ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctionPtr fn, char *fn_name, zval *return_value, zval *soap_headers) { @@ -191,7 +213,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio tmp = get_node(fault->children, "faultstring"); if (tmp != NULL && tmp->children != NULL) { zval zv; - master_to_zval(&zv, get_conversion(IS_STRING), tmp); + master_to_zval_with_doc_cleanup(&zv, get_conversion(IS_STRING), tmp, response); convert_to_string(&zv) faultstring = Z_STR(zv); } @@ -199,14 +221,14 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio tmp = get_node(fault->children, "faultactor"); if (tmp != NULL && tmp->children != NULL) { zval zv; - master_to_zval(&zv, get_conversion(IS_STRING), tmp); + master_to_zval_with_doc_cleanup(&zv, get_conversion(IS_STRING), tmp, response); convert_to_string(&zv) faultactor = Z_STR(zv); } tmp = get_node(fault->children, "detail"); if (tmp != NULL) { - master_to_zval(&details, NULL, tmp); + master_to_zval_with_doc_cleanup(&details, NULL, tmp, response); } } else { tmp = get_node(fault->children, "Code"); @@ -223,7 +245,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio tmp = get_node(tmp->children,"Text"); if (tmp != NULL && tmp->children != NULL) { zval zv; - master_to_zval(&zv, get_conversion(IS_STRING), tmp); + master_to_zval_with_doc_cleanup(&zv, get_conversion(IS_STRING), tmp, response); convert_to_string(&zv) faultstring = Z_STR(zv); } @@ -231,7 +253,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio tmp = get_node(fault->children,"Detail"); if (tmp != NULL) { - master_to_zval(&details, NULL, tmp); + master_to_zval_with_doc_cleanup(&details, NULL, tmp, response); } } add_soap_fault(this_ptr, faultcode, faultstring ? ZSTR_VAL(faultstring) : NULL, faultactor ? ZSTR_VAL(faultactor) : NULL, &details); @@ -324,9 +346,9 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio } else { /* Decoding value of parameter */ if (param != NULL) { - master_to_zval(&tmp, param->encode, val); + master_to_zval_with_doc_cleanup(&tmp, param->encode, val, response); } else { - master_to_zval(&tmp, NULL, val); + master_to_zval_with_doc_cleanup(&tmp, NULL, val, response); } } add_assoc_zval(return_value, param->paramName, &tmp); @@ -347,7 +369,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio zval tmp; zval *arr; - master_to_zval(&tmp, NULL, val); + master_to_zval_with_doc_cleanup(&tmp, NULL, val, response); if (val->name) { if ((arr = zend_hash_str_find(Z_ARRVAL_P(return_value), (char*)val->name, strlen((char*)val->name))) != NULL) { add_next_index_zval(arr, &tmp); @@ -412,7 +434,7 @@ bool parse_packet_soap(zval *this_ptr, char *buffer, int buffer_size, sdlFunctio } smart_str_free(&key); } - master_to_zval(&val, enc, trav); + master_to_zval_with_doc_cleanup(&val, enc, trav, response); add_assoc_zval(soap_headers, (char*)trav->name, &val); } trav = trav->next; diff --git a/ext/soap/soap.c b/ext/soap/soap.c index a171362d3178..ce12aeaf364c 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2408,9 +2408,19 @@ static void do_soap_call(zend_execute_data *execute_data, request = NULL; if (ret && Z_TYPE(response) == IS_STRING) { + bool parse_bailout = false; + encode_reset_ns(); - ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers); + zend_try { + ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), fn, NULL, return_value, output_headers); + } zend_catch { + parse_bailout = true; + } zend_end_try(); encode_finish(); + if (parse_bailout) { + zval_ptr_dtor(&response); + zend_bailout(); + } } zval_ptr_dtor(&response); @@ -2452,9 +2462,19 @@ static void do_soap_call(zend_execute_data *execute_data, request = NULL; if (ret && Z_TYPE(response) == IS_STRING) { + bool parse_bailout = false; + encode_reset_ns(); - ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, NULL, return_value, output_headers); + zend_try { + ret = parse_packet_soap(this_ptr, Z_STRVAL(response), Z_STRLEN(response), NULL, NULL, return_value, output_headers); + } zend_catch { + parse_bailout = true; + } zend_end_try(); encode_finish(); + if (parse_bailout) { + zval_ptr_dtor(&response); + zend_bailout(); + } } zval_ptr_dtor(&response); diff --git a/ext/soap/tests/soap_array_index_overflow.phpt b/ext/soap/tests/soap_array_index_overflow.phpt new file mode 100644 index 000000000000..ae481ee317ff --- /dev/null +++ b/ext/soap/tests/soap_array_index_overflow.phpt @@ -0,0 +1,89 @@ +--TEST-- +SOAP array index overflow is rejected +--EXTENSIONS-- +soap +--FILE-- +response; + } +} + +function soap_response(string $attributes, string $itemAttributes = ''): string { + return << + + + + + value + + + + +XML; +} + +function test_overflow(string $name, string $response): void { + $client = new TestSoapClient(NULL, [ + 'location' => 'test://', + 'uri' => 'http://example.org/', + 'exceptions' => true, + ]); + $client->response = $response; + + try { + $client->test(); + echo "$name: no fault\n"; + } catch (SoapFault $e) { + echo "$name: $e->faultstring\n"; + } +} + +function test_boundary_position(): void { + $client = new TestSoapClient(NULL, [ + 'location' => 'test://', + 'uri' => 'http://example.org/', + 'exceptions' => true, + ]); + $client->response = soap_response( + 'SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array"', + 'SOAP-ENC:position="[2147483646]"' + ); + + var_dump($client->test()); +} + +test_overflow( + 'arrayType', + soap_response('SOAP-ENC:arrayType="xsd:string[2147483648]" xsi:type="SOAP-ENC:Array"') +); + +test_overflow( + 'offset', + soap_response('SOAP-ENC:arrayType="xsd:string[1]" SOAP-ENC:offset="[2147483648]" xsi:type="SOAP-ENC:Array"') +); + +test_overflow( + 'position', + soap_response('SOAP-ENC:arrayType="xsd:string[1]" xsi:type="SOAP-ENC:Array"', 'SOAP-ENC:position="[2147483647]"') +); + +test_boundary_position(); +?> +--EXPECT-- +arrayType: SOAP-ERROR: Encoding: array index out of range +offset: SOAP-ERROR: Encoding: array index out of range +position: SOAP-ERROR: Encoding: array index out of range +array(1) { + [2147483646]=> + string(5) "value" +}