mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Merge branch 'PHP-8.1.33-security' into PHP-8.1
This commit is contained in:
commit
13bc0e2367
11 changed files with 344 additions and 29 deletions
12
NEWS
12
NEWS
|
@ -1,8 +1,18 @@
|
||||||
PHP NEWS
|
PHP NEWS
|
||||||
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||
?? ??? ????, PHP 8.1.33
|
03 Jul 2025, PHP 8.1.33
|
||||||
|
|
||||||
|
- PGSQL:
|
||||||
|
. Fixed GHSA-hrwm-9436-5mv3 (pgsql extension does not check for errors during
|
||||||
|
escaping). (CVE-2025-1735) (Jakub Zelenka)
|
||||||
|
|
||||||
|
- SOAP:
|
||||||
|
. 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)
|
||||||
|
|
||||||
13 Mar 2025, PHP 8.1.32
|
13 Mar 2025, PHP 8.1.32
|
||||||
|
|
||||||
|
|
|
@ -354,11 +354,15 @@ static zend_string* pgsql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
|
||||||
zend_string *quoted_str;
|
zend_string *quoted_str;
|
||||||
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
|
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
|
||||||
size_t tmp_len;
|
size_t tmp_len;
|
||||||
|
int err;
|
||||||
|
|
||||||
switch (paramtype) {
|
switch (paramtype) {
|
||||||
case PDO_PARAM_LOB:
|
case PDO_PARAM_LOB:
|
||||||
/* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
|
/* escapedlen returned by PQescapeBytea() accounts for trailing 0 */
|
||||||
escaped = PQescapeByteaConn(H->server, (unsigned char *)ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), &tmp_len);
|
escaped = PQescapeByteaConn(H->server, (unsigned char *)ZSTR_VAL(unquoted), ZSTR_LEN(unquoted), &tmp_len);
|
||||||
|
if (escaped == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
quotedlen = tmp_len + 1;
|
quotedlen = tmp_len + 1;
|
||||||
quoted = emalloc(quotedlen + 1);
|
quoted = emalloc(quotedlen + 1);
|
||||||
memcpy(quoted+1, escaped, quotedlen-2);
|
memcpy(quoted+1, escaped, quotedlen-2);
|
||||||
|
@ -370,7 +374,11 @@ static zend_string* pgsql_handle_quoter(pdo_dbh_t *dbh, const zend_string *unquo
|
||||||
default:
|
default:
|
||||||
quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
|
quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3);
|
||||||
quoted[0] = '\'';
|
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 + 1] = '\'';
|
||||||
quoted[quotedlen + 2] = '\0';
|
quoted[quotedlen + 2] = '\0';
|
||||||
quotedlen += 2;
|
quotedlen += 2;
|
||||||
|
|
24
ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
Normal file
24
ext/pdo_pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
Normal 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)
|
|
@ -3297,8 +3297,14 @@ PHP_FUNCTION(pg_escape_string)
|
||||||
|
|
||||||
to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
|
to = zend_string_safe_alloc(ZSTR_LEN(from), 2, 0, 0);
|
||||||
if (link) {
|
if (link) {
|
||||||
|
int err;
|
||||||
pgsql = link->conn;
|
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
|
} else
|
||||||
{
|
{
|
||||||
ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
|
ZSTR_LEN(to) = PQescapeString(ZSTR_VAL(to), ZSTR_VAL(from), ZSTR_LEN(from));
|
||||||
|
@ -3341,6 +3347,10 @@ PHP_FUNCTION(pg_escape_bytea)
|
||||||
} else {
|
} else {
|
||||||
to = (char *)PQescapeBytea((unsigned char *)ZSTR_VAL(from), ZSTR_LEN(from), &to_len);
|
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' */
|
RETVAL_STRINGL(to, to_len-1); /* to_len includes additional '\0' */
|
||||||
PQfreemem(to);
|
PQfreemem(to);
|
||||||
|
@ -4257,7 +4267,7 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
|
||||||
char *escaped;
|
char *escaped;
|
||||||
smart_str querystr = {0};
|
smart_str querystr = {0};
|
||||||
size_t new_len;
|
size_t new_len;
|
||||||
int i, num_rows;
|
int i, num_rows, err;
|
||||||
zval elem;
|
zval elem;
|
||||||
|
|
||||||
ZEND_ASSERT(ZSTR_LEN(table_name) != 0);
|
ZEND_ASSERT(ZSTR_LEN(table_name) != 0);
|
||||||
|
@ -4296,7 +4306,14 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
|
||||||
"WHERE a.attnum > 0 AND c.relname = '");
|
"WHERE a.attnum > 0 AND c.relname = '");
|
||||||
}
|
}
|
||||||
escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
|
escaped = (char *)safe_emalloc(strlen(tmp_name2), 2, 1);
|
||||||
new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), NULL);
|
new_len = PQescapeStringConn(pg_link, escaped, tmp_name2, strlen(tmp_name2), &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) {
|
if (new_len) {
|
||||||
smart_str_appendl(&querystr, escaped, new_len);
|
smart_str_appendl(&querystr, escaped, new_len);
|
||||||
}
|
}
|
||||||
|
@ -4304,7 +4321,14 @@ PHP_PGSQL_API zend_result php_pgsql_meta_data(PGconn *pg_link, const zend_string
|
||||||
|
|
||||||
smart_str_appends(&querystr, "' AND n.nspname = '");
|
smart_str_appends(&querystr, "' AND n.nspname = '");
|
||||||
escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
|
escaped = (char *)safe_emalloc(strlen(tmp_name), 2, 1);
|
||||||
new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), NULL);
|
new_len = PQescapeStringConn(pg_link, escaped, tmp_name, strlen(tmp_name), &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) {
|
if (new_len) {
|
||||||
smart_str_appendl(&querystr, escaped, new_len);
|
smart_str_appendl(&querystr, escaped, new_len);
|
||||||
}
|
}
|
||||||
|
@ -4565,7 +4589,7 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
|
||||||
{
|
{
|
||||||
zend_string *field = NULL;
|
zend_string *field = NULL;
|
||||||
zval meta, *def, *type, *not_null, *has_default, *is_enum, *val, new_val;
|
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;
|
php_pgsql_data_type data_type;
|
||||||
|
|
||||||
ZEND_ASSERT(pg_link != NULL);
|
ZEND_ASSERT(pg_link != NULL);
|
||||||
|
@ -4818,8 +4842,13 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
|
||||||
/* PostgreSQL ignores \0 */
|
/* PostgreSQL ignores \0 */
|
||||||
str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
|
str = zend_string_alloc(Z_STRLEN_P(val) * 2, 0);
|
||||||
/* better to use PGSQLescapeLiteral since PGescapeStringConn does not handle special \ */
|
/* 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),
|
||||||
ZVAL_STR(&new_val, php_pgsql_add_quotes(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);
|
zend_string_release_ex(str, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -4842,7 +4871,15 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
|
||||||
}
|
}
|
||||||
PGSQL_CONV_CHECK_IGNORE();
|
PGSQL_CONV_CHECK_IGNORE();
|
||||||
if (err) {
|
if (err) {
|
||||||
php_error_docref(NULL, E_NOTICE, "Expects NULL, string, long or double value for PostgreSQL '%s' (%s)", Z_STRVAL_P(type), ZSTR_VAL(field));
|
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 {
|
||||||
|
php_error_docref(NULL, E_NOTICE,
|
||||||
|
"Expects NULL, string, long or double value for PostgreSQL '%s' (%s)",
|
||||||
|
Z_STRVAL_P(type), ZSTR_VAL(field));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -5113,6 +5150,11 @@ PHP_PGSQL_API zend_result php_pgsql_convert(PGconn *pg_link, const zend_string *
|
||||||
zend_string *tmp_zstr;
|
zend_string *tmp_zstr;
|
||||||
|
|
||||||
tmp = PQescapeByteaConn(pg_link, (unsigned char *)Z_STRVAL_P(val), Z_STRLEN_P(val), &to_len);
|
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' */
|
tmp_zstr = zend_string_init((char *)tmp, to_len - 1, false); /* PQescapeBytea's to_len includes additional '\0' */
|
||||||
PQfreemem(tmp);
|
PQfreemem(tmp);
|
||||||
|
|
||||||
|
@ -5191,6 +5233,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);
|
zend_hash_update(Z_ARRVAL_P(result), field, &new_val);
|
||||||
} else {
|
} else {
|
||||||
char *escaped = PQescapeIdentifier(pg_link, ZSTR_VAL(field), ZSTR_LEN(field));
|
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);
|
add_assoc_zval(result, escaped, &new_val);
|
||||||
PQfreemem(escaped);
|
PQfreemem(escaped);
|
||||||
}
|
}
|
||||||
|
@ -5269,7 +5317,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" */
|
/* schema.table should be "schema"."table" */
|
||||||
const char *dot = memchr(ZSTR_VAL(table), '.', ZSTR_LEN(table));
|
const char *dot = memchr(ZSTR_VAL(table), '.', ZSTR_LEN(table));
|
||||||
|
@ -5279,6 +5327,10 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const z
|
||||||
smart_str_appendl(querystr, ZSTR_VAL(table), len);
|
smart_str_appendl(querystr, ZSTR_VAL(table), len);
|
||||||
} else {
|
} else {
|
||||||
char *escaped = PQescapeIdentifier(pg_link, ZSTR_VAL(table), len);
|
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);
|
smart_str_appends(querystr, escaped);
|
||||||
PQfreemem(escaped);
|
PQfreemem(escaped);
|
||||||
}
|
}
|
||||||
|
@ -5291,11 +5343,17 @@ static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const z
|
||||||
smart_str_appendl(querystr, after_dot, len);
|
smart_str_appendl(querystr, after_dot, len);
|
||||||
} else {
|
} else {
|
||||||
char *escaped = PQescapeIdentifier(pg_link, after_dot, len);
|
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_appendc(querystr, '.');
|
||||||
smart_str_appends(querystr, escaped);
|
smart_str_appends(querystr, escaped);
|
||||||
PQfreemem(escaped);
|
PQfreemem(escaped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -5316,7 +5374,9 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
|
||||||
ZVAL_UNDEF(&converted);
|
ZVAL_UNDEF(&converted);
|
||||||
if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
|
if (zend_hash_num_elements(Z_ARRVAL_P(var_array)) == 0) {
|
||||||
smart_str_appends(&querystr, "INSERT INTO ");
|
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");
|
smart_str_appends(&querystr, " DEFAULT VALUES");
|
||||||
|
|
||||||
goto no_values;
|
goto no_values;
|
||||||
|
@ -5332,7 +5392,9 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
|
||||||
}
|
}
|
||||||
|
|
||||||
smart_str_appends(&querystr, "INSERT INTO ");
|
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, " (");
|
smart_str_appends(&querystr, " (");
|
||||||
|
|
||||||
ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
|
ZEND_HASH_FOREACH_STR_KEY(Z_ARRVAL_P(var_array), fld) {
|
||||||
|
@ -5342,6 +5404,10 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
|
||||||
}
|
}
|
||||||
if (opt & PGSQL_DML_ESCAPE) {
|
if (opt & PGSQL_DML_ESCAPE) {
|
||||||
tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
|
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);
|
smart_str_appends(&querystr, tmp);
|
||||||
PQfreemem(tmp);
|
PQfreemem(tmp);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5353,15 +5419,19 @@ PHP_PGSQL_API zend_result php_pgsql_insert(PGconn *pg_link, const zend_string *t
|
||||||
smart_str_appends(&querystr, ") VALUES (");
|
smart_str_appends(&querystr, ") VALUES (");
|
||||||
|
|
||||||
/* make values string */
|
/* 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 */
|
/* we can avoid the key_type check here, because we tested it in the other loop */
|
||||||
switch (Z_TYPE_P(val)) {
|
switch (Z_TYPE_P(val)) {
|
||||||
case IS_STRING:
|
case IS_STRING:
|
||||||
if (opt & PGSQL_DML_ESCAPE) {
|
if (opt & PGSQL_DML_ESCAPE) {
|
||||||
size_t new_len;
|
int error;
|
||||||
char *tmp;
|
char *tmp = safe_emalloc(Z_STRLEN_P(val), 2, 1);
|
||||||
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), &error);
|
||||||
new_len = PQescapeStringConn(pg_link, tmp, Z_STRVAL_P(val), Z_STRLEN_P(val), NULL);
|
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_appendc(&querystr, '\'');
|
||||||
smart_str_appendl(&querystr, tmp, new_len);
|
smart_str_appendl(&querystr, tmp, new_len);
|
||||||
smart_str_appendc(&querystr, '\'');
|
smart_str_appendc(&querystr, '\'');
|
||||||
|
@ -5517,6 +5587,10 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
|
||||||
}
|
}
|
||||||
if (opt & PGSQL_DML_ESCAPE) {
|
if (opt & PGSQL_DML_ESCAPE) {
|
||||||
char *tmp = PQescapeIdentifier(pg_link, ZSTR_VAL(fld), ZSTR_LEN(fld) + 1);
|
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);
|
smart_str_appends(querystr, tmp);
|
||||||
PQfreemem(tmp);
|
PQfreemem(tmp);
|
||||||
} else {
|
} else {
|
||||||
|
@ -5532,8 +5606,14 @@ static inline int build_assignment_string(PGconn *pg_link, smart_str *querystr,
|
||||||
switch (Z_TYPE_P(val)) {
|
switch (Z_TYPE_P(val)) {
|
||||||
case IS_STRING:
|
case IS_STRING:
|
||||||
if (opt & PGSQL_DML_ESCAPE) {
|
if (opt & PGSQL_DML_ESCAPE) {
|
||||||
|
int error;
|
||||||
char *tmp = (char *)safe_emalloc(Z_STRLEN_P(val), 2, 1);
|
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_appendc(querystr, '\'');
|
||||||
smart_str_appendl(querystr, tmp, new_len);
|
smart_str_appendl(querystr, tmp, new_len);
|
||||||
smart_str_appendc(querystr, '\'');
|
smart_str_appendc(querystr, '\'');
|
||||||
|
@ -5601,7 +5681,9 @@ PHP_PGSQL_API zend_result php_pgsql_update(PGconn *pg_link, const zend_string *t
|
||||||
}
|
}
|
||||||
|
|
||||||
smart_str_appends(&querystr, "UPDATE ");
|
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 ");
|
smart_str_appends(&querystr, " SET ");
|
||||||
|
|
||||||
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
|
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(var_array), 0, ",", 1, opt))
|
||||||
|
@ -5704,7 +5786,9 @@ PHP_PGSQL_API zend_result php_pgsql_delete(PGconn *pg_link, const zend_string *t
|
||||||
}
|
}
|
||||||
|
|
||||||
smart_str_appends(&querystr, "DELETE FROM ");
|
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 ");
|
smart_str_appends(&querystr, " WHERE ");
|
||||||
|
|
||||||
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
|
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
|
||||||
|
@ -5844,7 +5928,9 @@ PHP_PGSQL_API zend_result php_pgsql_select(PGconn *pg_link, const zend_string *t
|
||||||
}
|
}
|
||||||
|
|
||||||
smart_str_appends(&querystr, "SELECT * FROM ");
|
smart_str_appends(&querystr, "SELECT * FROM ");
|
||||||
build_tablename(&querystr, pg_link, table);
|
if (build_tablename(&querystr, pg_link, table) == FAILURE) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
smart_str_appends(&querystr, " WHERE ");
|
smart_str_appends(&querystr, " WHERE ");
|
||||||
|
|
||||||
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
|
if (build_assignment_string(pg_link, &querystr, Z_ARRVAL_P(ids_array), 1, " AND ", sizeof(" AND ")-1, opt))
|
||||||
|
|
64
ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
Normal file
64
ext/pgsql/tests/ghsa-hrwm-9436-5mv3.phpt
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
--TEST--
|
||||||
|
#GHSA-hrwm-9436-5mv3: pgsql extension does not check for errors during escaping
|
||||||
|
--EXTENSIONS--
|
||||||
|
pgsql
|
||||||
|
--SKIPIF--
|
||||||
|
<?php include("skipif.inc"); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
include '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)
|
|
@ -4019,8 +4019,10 @@ static xmlNodePtr serialize_zval(zval *val, sdlParamPtr param, char *paramName,
|
||||||
}
|
}
|
||||||
xmlParam = master_to_xml(enc, val, style, parent);
|
xmlParam = master_to_xml(enc, val, style, parent);
|
||||||
zval_ptr_dtor(&defval);
|
zval_ptr_dtor(&defval);
|
||||||
if (!strcmp((char*)xmlParam->name, "BOGUS")) {
|
if (xmlParam != NULL) {
|
||||||
xmlNodeSetName(xmlParam, BAD_CAST(paramName));
|
if (xmlParam->name == NULL || strcmp((char*)xmlParam->name, "BOGUS") == 0) {
|
||||||
|
xmlNodeSetName(xmlParam, BAD_CAST(paramName));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return xmlParam;
|
return xmlParam;
|
||||||
}
|
}
|
||||||
|
|
48
ext/soap/tests/soap_qname_crash.phpt
Normal file
48
ext/soap/tests/soap_qname_crash.phpt
Normal 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>
|
|
@ -23,6 +23,28 @@
|
||||||
#include "php_network.h"
|
#include "php_network.h"
|
||||||
#include "file.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() */
|
/* {{{ php_fsockopen() */
|
||||||
|
|
||||||
static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
|
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) {
|
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) {
|
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 {
|
} else {
|
||||||
hostname_len = host_len;
|
hostname_len = host_len;
|
||||||
hostname = host;
|
hostname = host;
|
||||||
|
|
21
ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
Normal file
21
ext/standard/tests/network/ghsa-3cr5-j632-f35r.phpt
Normal 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)
|
26
ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
Normal file
26
ext/standard/tests/streams/ghsa-3cr5-j632-f35r.phpt
Normal 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)
|
|
@ -581,12 +581,15 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *po
|
||||||
char *colon;
|
char *colon;
|
||||||
char *host = NULL;
|
char *host = NULL;
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
if (memchr(str, '\0', str_len)) {
|
||||||
char *p;
|
*err = ZSTR_INIT_LITERAL("The hostname must not contain null bytes", 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
if (*(str) == '[' && str_len > 1) {
|
if (*(str) == '[' && str_len > 1) {
|
||||||
/* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
|
/* 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 (!p || *(p + 1) != ':') {
|
||||||
if (get_err) {
|
if (get_err) {
|
||||||
*err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
|
*err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue