Compare commits

...

7 commits

Author SHA1 Message Date
Saki Takamachi
5b61b6dd83
Update versions for PHP 8.4.10 2025-07-02 11:22:42 +09:00
Saki Takamachi
f600f86ac4
Update versions for PHP 8.4.10 2025-07-02 11:13:24 +09:00
Jakub Zelenka
80637d11b3
Update NEWS with entries for security fixes 2025-07-02 09:00:09 +09:00
Gina Peter Banyard
758e1e3192
ext/dom: Fix new MSVC compiler warning
Closes GH-18889
2025-07-02 09:00:09 +09:00
Ahmed Lekssays
158aa14167
Fix GHSA-453j-q27h-5p8x
Libxml versions prior to 2.13 cannot correctly handle a call to
xmlNodeSetName() with a name longer than 2G. It will leave the node
object in an invalid state with a NULL name. This later causes a NULL
pointer dereference when using the name during message serialization.

To solve this, implement a workaround that resets the name to the
sentinel name if this situation arises.

Versions of libxml of 2.13 and higher are not affected.

This can be exploited if a SoapVar is created with a fully qualified
name that is longer than 2G. This would be possible if some application
code uses a namespace prefix from an untrusted source like from a remote
SOAP service.

Co-authored-by: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
2025-07-02 09:00:09 +09:00
Jakub Zelenka
2e37a4d8aa
Fix GHSA-hrwm-9436-5mv3: pgsql escaping no error checks
This adds error checks for escape function is pgsql and pdo_pgsql
extensions. It prevents possibility of storing not properly escaped
data which could potentially lead to some security issues.
2025-07-02 09:00:08 +09:00
Jakub Zelenka
9234b0d62c
Fix GHSA-3cr5-j632-f35r: Null byte in hostnames
This fixes stream_socket_client() and fsockopen().

Specifically it adds a check to parse_ip_address_ex and it also makes
sure that the \0 is not ignored in fsockopen() hostname formatting.
2025-07-02 09:00:08 +09:00
15 changed files with 351 additions and 37 deletions

14
NEWS
View file

@ -1,6 +1,6 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.4.9
03 Jul 2025, PHP 8.4.10
- BcMath:
. Fixed bug GH-18641 (Accessing a BcMath\Number property by ref crashes).
@ -49,6 +49,10 @@ PHP NEWS
. Fixed bug #74796 (Requests through http proxy set peer name).
(Jakub Zelenka)
- PGSQL:
. Fixed GHSA-hrwm-9436-5mv3 (pgsql extension does not check for errors during
escaping). (CVE-2025-1735) (Jakub Zelenka)
- PDO ODBC:
. Fix memory leak if WideCharToMultiByte() fails. (nielsdos)
@ -79,8 +83,14 @@ PHP NEWS
. Fixed bug GH-18597 (Heap-buffer-overflow in zend_alloc.c when assigning
string with UTF-8 bytes). (nielsdos)
- Soap:
- SOAP:
. Fix memory leaks in php_http.c when call_user_function() fails. (nielsdos)
. Fixed GHSA-453j-q27h-5p8x (NULL Pointer Dereference in PHP SOAP Extension
via Large XML Namespace Prefix). (CVE-2025-6491) (Lekssays, nielsdos)
- Standard:
. Fixed GHSA-3cr5-j632-f35r (Null byte termination in hostnames).
(CVE-2025-1220) (Jakub Zelenka)
- Tidy:
. Fix memory leak in tidy output handler on error. (nielsdos)

View file

@ -20,7 +20,7 @@
#ifndef ZEND_H
#define ZEND_H
#define ZEND_VERSION "4.4.9-dev"
#define ZEND_VERSION "4.4.10"
#define ZEND_ENGINE_3

View file

@ -17,7 +17,7 @@ dnl Basic autoconf initialization, generation of config.nice.
dnl ----------------------------------------------------------------------------
AC_PREREQ([2.68])
AC_INIT([PHP],[8.4.9-dev],[https://github.com/php/php-src/issues],[php],[https://www.php.net])
AC_INIT([PHP],[8.4.10],[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

View file

@ -752,7 +752,7 @@ static bool dom_parse_decode_encode_finish(
static bool check_options_validity(uint32_t arg_num, zend_long options)
{
const zend_long VALID_OPTIONS = XML_PARSE_NOERROR | XML_PARSE_COMPACT | HTML_PARSE_NOIMPLIED | DOM_HTML_NO_DEFAULT_NS;
const zend_long VALID_OPTIONS = HTML_PARSE_NOERROR | HTML_PARSE_COMPACT | HTML_PARSE_NOIMPLIED | DOM_HTML_NO_DEFAULT_NS;
if ((options & ~VALID_OPTIONS) != 0) {
zend_argument_value_error(arg_num, "contains invalid flags (allowed flags: "
"LIBXML_NOERROR, "

View file

@ -367,11 +367,15 @@ static zend_string* pgsql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
zend_string *quoted_str;
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
size_t tmp_len;
int err;
switch (paramtype) {
case PDO_PARAM_LOB:
/* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
escaped = PQescapeByteaConn(H->server, (unsigned char *)ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), &tmp_len);
if (escaped == NULL) {
return NULL;
}
quotedlen = tmp_len + 1;
quoted = emalloc(quotedlen + 1);
memcpy(quoted+1, escaped, quotedlen-2);
@ -383,7 +387,11 @@ static zend_string* pgsql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
default:
quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
quoted[0] = '\'';
quotedlen = PQescapeStringConn(H->server, quoted + 1, ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), NULL);
quotedlen = PQescapeStringConn(H->server, quoted + 1, ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), &err);
if (err) {
efree(quoted);
return NULL;
}
quoted[quotedlen + 1] = '\'';
quoted[quotedlen + 2] = '\0';
quotedlen += 2;

View file

@ -0,0 +1,24 @@
--TEST--
#GHSA-hrwm-9436-5mv3: pdo_pgsql extension does not check for errors during escaping
--EXTENSIONS--
pdo
pdo_pgsql
--SKIPIF--
<?php
require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
require_once dirname(__FILE__) . '/config.inc';
PDOTest::skip();
?>
--FILE--
<?php
require_once dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
require_once dirname(__FILE__) . '/config.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$invalid = "ABC\xff\x30';";
var_dump($db->quote($invalid));
?>
--EXPECT--
bool(false)

View file

@ -3528,8 +3528,14 @@ PHP_FUNCTION(pg_escape_string)
to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
if (link) {
int err;
pgsql = link->conn;
ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), NULL);
ZSTR_LEN(to) = PQescapeStringConn(pgsql, ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from), &err);
if (err) {
zend_argument_value_error(ZEND_NUM_ARGS(), "Escaping string failed");
zend_string_efree(to);
RETURN_THROWS();
}
} else
{
ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
@ -3575,6 +3581,10 @@ PHP_FUNCTION(pg_escape_bytea)
} else {
to = (char *)PQescapeBytea((unsigned char *)ZSTR_VAL(from), ZSTR_LEN(from), &to_len);
}
if (to == NULL) {
zend_argument_value_error(ZEND_NUM_ARGS(), "Escape failure");
RETURN_THROWS();
}
RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
PQfreemem(to);
@ -4523,7 +4533,7 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
char *escaped;
smart_str querystr = {0};
size_t new_len, len;
int i, num_rows;
int i, num_rows, err;
zval elem;
ZEND_ASSERT(ZSTR_LEN(table_name) != 0);
@ -4562,7 +4572,14 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
}
len = strlen(tmp_name2);
escaped = (char *)safe_emalloc(len, 2, 1);
new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, len, NULL);
new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, len, &err);
if (err) {
php_error_docref(NULL, E_WARNING, "Escaping table name '%s' failed", ZSTR_VAL(table_name));
efree(src);
efree(escaped);
smart_str_free(&querystr);
return FAILURE;
}
if (new_len) {
smart_str_appendl(&querystr, escaped, new_len);
}
@ -4571,7 +4588,14 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
smart_str_appends(&querystr, "' AND n.nspname = '");
len = strlen(tmp_name);
escaped = (char *)safe_emalloc(len, 2, 1);
new_len = PQescapeStringConn(pg_link, escaped, tmp_name, len, NULL);
new_len = PQescapeStringConn(pg_link, escaped, tmp_name, len, &err);
if (err) {
php_error_docref(NULL, E_WARNING, "Escaping table namespace '%s' failed", ZSTR_VAL(table_name));
efree(src);
efree(escaped);
smart_str_free(&querystr);
return FAILURE;
}
if (new_len) {
smart_str_appendl(&querystr, escaped, new_len);
}
@ -4826,7 +4850,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
{
zend_string *field = NULL;
zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
int err = 0, skip_field;
int err = 0, escape_err = 0, skip_field;
php_pgsql_data_type data_type;
ZEND_ASSERT(pg_link != NULL);
@ -5072,8 +5096,13 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
/* PostgreSQL ignores \0 */
str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
/* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str), Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
ZSTR_LEN(str) = PQescapeStringConn(pg_link, ZSTR_VAL(str),
Z_STRVAL_P(val), Z_STRLEN_P(val), &escape_err);
if (escape_err) {
err = 1;
} else {
ZVAL_STR(&new_val, php_pgsql_add_quotes(str));
}
zend_string_release_ex(str, false);
}
break;
@ -5096,7 +5125,14 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
}
PGSQL_CONV_CHECK_IGNORE();
if (err) {
zend_type_error("%s(): Field \"%s\" must be of type string|null, %s given", get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
if (escape_err) {
php_error_docref(NULL, E_NOTICE,
"String value escaping failed for PostgreSQL '%s' (%s)",
Z_STRVAL_P(type), ZSTR_VAL(field));
} else {
zend_type_error("%s(): Field \"%s\" must be of type string|null, %s given",
get_active_function_name(), ZSTR_VAL(field), Z_STRVAL_P(type));
}
}
break;
@ -5330,6 +5366,11 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
zend_string *tmp_zstr;
tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val), &to_len);
if (tmp == NULL) {
php_error_docref(NULL, E_NOTICE, "Escaping value failed for %s field (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
err = 1;
break;
}
tmp_zstr = zend_string_init((char *)tmp, to_len - 1, false); /* PQescapeBytea's to_len includes additional '\0' */
PQfreemem(tmp);
@ -5406,6 +5447,12 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
} else {
char *escaped = PQescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
if (escaped == NULL) {
/* This cannot fail because of invalid string but only due to failed memory allocation */
php_error_docref(NULL, E_NOTICE, "Escaping field '%s' failed", ZSTR_VAL(field));
err = 1;
break;
}
add_assoc_zval(result, escaped, &new_val);
PQfreemem(escaped);
}
@ -5488,7 +5535,7 @@ static bool do_exec(smart_str *querystr, ExecStatusType expect, PGconn *pg_link,
}
/* }}} */
static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const zend_string *table) /* {{{ */
static inline zend_result build_tablename(smart_str *querystr, PGconn *pg_link, const zend_string *table) /* {{{ */
{
/* schema.table should be "schema"."table" */
const char *dot = memchr(ZSTR_VAL(table), '.', ZSTR_LEN(table));
@ -5498,6 +5545,10 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const z
smart_str_appendl(querystr, ZSTR_VAL(table), len);
} else {
char *escaped = PQescapeIdentifier(pg_link, ZSTR_VAL(table), len);
if (escaped == NULL) {
php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", ZSTR_VAL(table));
return FAILURE;
}
smart_str_appends(querystr, escaped);
PQfreemem(escaped);
}
@ -5510,11 +5561,17 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const z
smart_str_appendl(querystr, after_dot, len);
} else {
char *escaped = PQescapeIdentifier(pg_link, after_dot, len);
if (escaped == NULL) {
php_error_docref(NULL, E_NOTICE, "Failed to escape table name '%s'", ZSTR_VAL(table));
return FAILURE;
}
smart_str_appendc(querystr, '.');
smart_str_appends(querystr, escaped);
PQfreemem(escaped);
}
}
return SUCCESS;
}
/* }}} */
@ -5535,7 +5592,9 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
ZVAL_UNDEF(&converted);
if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
smart_str_appends(&querystr, "INSERT INTO ");
build_tablename(&querystr, pg_link, table);
if (build_tablename(&querystr, pg_link, table) == FAILURE) {
goto cleanup;
}
smart_str_appends(&querystr, " DEFAULT VALUES");
goto no_values;
@ -5551,7 +5610,9 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
}
smart_str_appends(&querystr, "INSERT INTO ");
build_tablename(&querystr, pg_link, table);
if (build_tablename(&querystr, pg_link, table) == FAILURE) {
goto cleanup;
}
smart_str_appends(&querystr, " (");
ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
@ -5561,6 +5622,10 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
}
if (opt & PGSQL_DML_ESCAPE) {
tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
if (tmp == NULL) {
php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld));
goto cleanup;
}
smart_str_appends(&querystr, tmp);
PQfreemem(tmp);
} else {
@ -5572,15 +5637,19 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
smart_str_appends(&querystr, ") VALUES (");
/* make values string */
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(var_array), val) {
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(var_array), fld, val) {
/* we can avoid the key_type check here, because we tested it in the other loop */
switch (Z_TYPE_P(val)) {
case IS_STRING:
if (opt & PGSQL_DML_ESCAPE) {
size_t new_len;
char *tmp;
tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
int error;
char *tmp = safe_emalloc(Z_STRLEN_P(val), 2, 1);
size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error);
if (error) {
php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld));
efree(tmp);
goto cleanup;
}
smart_str_appendc(&querystr, '\'');
smart_str_appendl(&querystr, tmp, new_len);
smart_str_appendc(&querystr, '\'');
@ -5738,6 +5807,10 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
}
if (opt & PGSQL_DML_ESCAPE) {
char *tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
if (tmp == NULL) {
php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s'", ZSTR_VAL(fld));
return -1;
}
smart_str_appends(querystr, tmp);
PQfreemem(tmp);
} else {
@ -5753,8 +5826,14 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
switch (Z_TYPE_P(val)) {
case IS_STRING:
if (opt & PGSQL_DML_ESCAPE) {
int error;
char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
size_t new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), &error);
if (error) {
php_error_docref(NULL, E_NOTICE, "Failed to escape field '%s' value", ZSTR_VAL(fld));
efree(tmp);
return -1;
}
smart_str_appendc(querystr, '\'');
smart_str_appendl(querystr, tmp, new_len);
smart_str_appendc(querystr, '\'');
@ -5822,7 +5901,9 @@ PHP_PGSQL_API zend_result php_pgsql_update(PGconn *pg_link, const zend_string *t
}
smart_str_appends(&querystr, "UPDATE ");
build_tablename(&querystr, pg_link, table);
if (build_tablename(&querystr, pg_link, table) == FAILURE) {
goto cleanup;
}
smart_str_appends(&querystr, " SET ");
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
@ -5928,7 +6009,9 @@ PHP_PGSQL_API zend_result php_pgsql_delete(PGconn *pg_link, const zend_string *t
}
smart_str_appends(&querystr, "DELETE FROM ");
build_tablename(&querystr, pg_link, table);
if (build_tablename(&querystr, pg_link, table) == FAILURE) {
goto cleanup;
}
smart_str_appends(&querystr, " WHERE ");
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
@ -6072,7 +6155,9 @@ PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *t
}
smart_str_appends(&querystr, "SELECT * FROM ");
build_tablename(&querystr, pg_link, table);
if (build_tablename(&querystr, pg_link, table) == FAILURE) {
goto cleanup;
}
if (is_valid_ids_array) {
smart_str_appends(&querystr, " WHERE ");

View file

@ -0,0 +1,64 @@
--TEST--
#GHSA-hrwm-9436-5mv3: pgsql extension does not check for errors during escaping
--EXTENSIONS--
pgsql
--SKIPIF--
<?php include("inc/skipif.inc"); ?>
--FILE--
<?php
include 'inc/config.inc';
define('FILE_NAME', __DIR__ . '/php.gif');
$db = pg_connect($conn_str);
pg_query($db, "DROP TABLE IF EXISTS ghsa_hrmw_9436_5mv3");
pg_query($db, "CREATE TABLE ghsa_hrmw_9436_5mv3 (bar text);");
// pg_escape_literal/pg_escape_identifier
$invalid = "ABC\xff\x30';";
$flags = PGSQL_DML_NO_CONV | PGSQL_DML_ESCAPE;
var_dump(pg_insert($db, $invalid, ['bar' => 'test'])); // table name str escape in php_pgsql_meta_data
var_dump(pg_insert($db, "$invalid.tbl", ['bar' => 'test'])); // schema name str escape in php_pgsql_meta_data
var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', ['bar' => $invalid])); // converted value str escape in php_pgsql_convert
var_dump(pg_insert($db, $invalid, [])); // ident escape in build_tablename
var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', [$invalid => 'foo'], $flags)); // ident escape for field php_pgsql_insert
var_dump(pg_insert($db, 'ghsa_hrmw_9436_5mv3', ['bar' => $invalid], $flags)); // str escape for field value in php_pgsql_insert
var_dump(pg_update($db, 'ghsa_hrmw_9436_5mv3', ['bar' => 'val'], [$invalid => 'test'], $flags)); // ident escape in build_assignment_string
var_dump(pg_update($db, 'ghsa_hrmw_9436_5mv3', ['bar' => 'val'], ['bar' => $invalid], $flags)); // invalid str escape in build_assignment_string
var_dump(pg_escape_literal($db, $invalid)); // pg_escape_literal escape
var_dump(pg_escape_identifier($db, $invalid)); // pg_escape_identifier escape
?>
--EXPECTF--
Warning: pg_insert(): Escaping table name 'ABC%s';' failed in %s on line %d
bool(false)
Warning: pg_insert(): Escaping table namespace 'ABC%s';.tbl' failed in %s on line %d
bool(false)
Notice: pg_insert(): String value escaping failed for PostgreSQL 'text' (bar) in %s on line %d
bool(false)
Notice: pg_insert(): Failed to escape table name 'ABC%s';' in %s on line %d
bool(false)
Notice: pg_insert(): Failed to escape field 'ABC%s';' in %s on line %d
bool(false)
Notice: pg_insert(): Failed to escape field 'bar' value in %s on line %d
bool(false)
Notice: pg_update(): Failed to escape field 'ABC%s';' in %s on line %d
bool(false)
Notice: pg_update(): Failed to escape field 'bar' value in %s on line %d
bool(false)
Warning: pg_escape_literal(): Failed to escape in %s on line %d
bool(false)
Warning: pg_escape_identifier(): Failed to escape in %s on line %d
bool(false)

View file

@ -4134,9 +4134,11 @@ static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, const char *param
}
xmlParam = master_to_xml(enc, val, style, parent);
zval_ptr_dtor(&defval);
if (!strcmp((char*)xmlParam->name, "BOGUS")) {
if (xmlParam != NULL) {
if (xmlParam->name == NULL || strcmp((char*)xmlParam->name, "BOGUS") == 0) {
xmlNodeSetName(xmlParam, BAD_CAST(paramName));
}
}
return xmlParam;
}
/* }}} */

View file

@ -0,0 +1,48 @@
--TEST--
Test SoapClient with excessively large QName prefix in SoapVar
--EXTENSIONS--
soap
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die("skip: 64-bit only");
?>
--INI--
memory_limit=6144M
--FILE--
<?php
class TestSoapClient extends SoapClient {
public function __doRequest(
$request,
$location,
$action,
$version,
$one_way = false,
): ?string {
die($request);
}
}
$prefix = str_repeat("A", 2 * 1024 * 1024 * 1024);
$qname = "{$prefix}:tag";
echo "Attempting to create SoapVar with very large QName\n";
$var = new SoapVar("value", XSD_QNAME, null, null, $qname);
echo "Attempting encoding\n";
$options = [
'location' => 'http://127.0.0.1/',
'uri' => 'urn:dummy',
'trace' => 1,
'exceptions' => true,
];
$client = new TestSoapClient(null, $options);
$client->__soapCall("DummyFunction", [$var]);
?>
--EXPECT--
Attempting to create SoapVar with very large QName
Attempting encoding
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:dummy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:DummyFunction><param0 xsi:type="xsd:QName">value</param0></ns1:DummyFunction></SOAP-ENV:Body></SOAP-ENV:Envelope>

View file

@ -23,6 +23,28 @@
#include "php_network.h"
#include "file.h"
static size_t php_fsockopen_format_host_port(char **message, const char *prefix, size_t prefix_len,
const char *host, size_t host_len, zend_long port)
{
char portbuf[32];
int portlen = snprintf(portbuf, sizeof(portbuf), ":" ZEND_LONG_FMT, port);
size_t total_len = prefix_len + host_len + portlen;
char *result = emalloc(total_len + 1);
if (prefix_len > 0) {
memcpy(result, prefix, prefix_len);
}
memcpy(result + prefix_len, host, host_len);
memcpy(result + prefix_len + host_len, portbuf, portlen);
result[total_len] = '\0';
*message = result;
return total_len;
}
/* {{{ php_fsockopen() */
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
@ -62,11 +84,12 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
}
if (persistent) {
spprintf(&hashkey, 0, "pfsockopen__%s:" ZEND_LONG_FMT, host, port);
php_fsockopen_format_host_port(&hashkey, "pfsockopen__", strlen("pfsockopen__"), host,
host_len, port);
}
if (port > 0) {
hostname_len = spprintf(&hostname, 0, "%s:" ZEND_LONG_FMT, host, port);
hostname_len = php_fsockopen_format_host_port(&hostname, "", 0, host, host_len, port);
} else {
hostname_len = host_len;
hostname = host;

View file

@ -0,0 +1,21 @@
--TEST--
GHSA-3cr5-j632-f35r: Null byte termination in fsockopen()
--FILE--
<?php
$server = stream_socket_server("tcp://localhost:0");
if (preg_match('/:(\d+)$/', stream_socket_get_name($server, false), $m)) {
$client = fsockopen("localhost\0.example.com", intval($m[1]));
var_dump($client);
if ($client) {
fclose($client);
}
}
fclose($server);
?>
--EXPECTF--
Warning: fsockopen(): Unable to connect to localhost:%d (The hostname must not contain null bytes) in %s
bool(false)

View file

@ -0,0 +1,26 @@
--TEST--
GHSA-3cr5-j632-f35r: Null byte termination in stream_socket_client()
--FILE--
<?php
$server = stream_socket_server("tcp://localhost:0");
$socket_name = stream_socket_get_name($server, false);
if (preg_match('/:(\d+)$/', $socket_name, $m)) {
$port = $m[1];
$client = stream_socket_client("tcp://localhost\0.example.com:$port");
var_dump($client);
if ($client) {
fclose($client);
}
} else {
echo "Could not extract port from socket name: $socket_name\n";
}
fclose($server);
?>
--EXPECTF--
Warning: stream_socket_client(): Unable to connect to tcp://localhost\0.example.com:%d (The hostname must not contain null bytes) in %s
bool(false)

View file

@ -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 9
#define PHP_EXTRA_VERSION "-dev"
#define PHP_VERSION "8.4.9-dev"
#define PHP_VERSION_ID 80409
#define PHP_RELEASE_VERSION 10
#define PHP_EXTRA_VERSION ""
#define PHP_VERSION "8.4.10"
#define PHP_VERSION_ID 80410

View file

@ -620,12 +620,15 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *po
char *colon;
char *host = NULL;
#ifdef HAVE_IPV6
char *p;
if (memchr(str, '\0', str_len)) {
*err = ZSTR_INIT_LITERAL("The hostname must not contain null bytes", 0);
return NULL;
}
#ifdef HAVE_IPV6
if (*(str) == '[' && str_len > 1) {
/* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
p = memchr(str + 1, ']', str_len - 2);
char *p = memchr(str + 1, ']', str_len - 2);
if (!p || *(p + 1) != ':') {
if (get_err) {
*err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);