1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Merge remote-tracking branch 'security/PHP-8.5.1-security' into PHP-8.5.1

* security/PHP-8.5.1-security:
  intl: Fix tests for icu update
  Suppress libxml deprecations
  Update NEWS with info about security issues
  Fix GHSA-www2-q4fc-65wf
  Fix GHSA-h96m-rvf9-jgm2
  Fix GHSA-8xr5-qppj-gvwj: PDO quoting result null deref
This commit is contained in:
Volker Dusch
2025-12-16 16:28:18 +01:00
13 changed files with 154 additions and 19 deletions

View File

@@ -1595,12 +1595,16 @@ PHP_METHOD(DOMDocument, save)
libxml_doc_props const* doc_props = dom_get_doc_props_read_only(intern->document);
bool format = doc_props->formatoutput;
if (options & LIBXML_SAVE_NOEMPTYTAG) {
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
saveempty = xmlSaveNoEmptyTags;
xmlSaveNoEmptyTags = 1;
ZEND_DIAGNOSTIC_IGNORED_END
}
zend_long bytes = intern->document->handlers->dump_doc_to_file(file, docp, format, (const char *) docp->encoding);
if (options & LIBXML_SAVE_NOEMPTYTAG) {
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
xmlSaveNoEmptyTags = saveempty;
ZEND_DIAGNOSTIC_IGNORED_END
}
if (bytes == -1) {
RETURN_FALSE;
@@ -1641,10 +1645,14 @@ static void dom_document_save_xml(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry
/* Save libxml2 global, override its value, and restore after saving (don't move me or risk breaking the state
* w.r.t. the implicit return in DOM_GET_OBJ). */
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
old_xml_save_no_empty_tags = xmlSaveNoEmptyTags;
xmlSaveNoEmptyTags = (options & LIBXML_SAVE_NOEMPTYTAG) ? 1 : 0;
ZEND_DIAGNOSTIC_IGNORED_END
res = intern->document->handlers->dump_node_to_str(docp, node, format, (const char *) docp->encoding);
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
xmlSaveNoEmptyTags = old_xml_save_no_empty_tags;
ZEND_DIAGNOSTIC_IGNORED_END
} else {
int converted_options = XML_SAVE_AS_XML;
if (options & XML_SAVE_NO_DECL) {
@@ -1655,10 +1663,14 @@ static void dom_document_save_xml(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry
}
/* Save libxml2 global, override its value, and restore after saving. */
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
old_xml_save_no_empty_tags = xmlSaveNoEmptyTags;
xmlSaveNoEmptyTags = (options & LIBXML_SAVE_NOEMPTYTAG) ? 1 : 0;
ZEND_DIAGNOSTIC_IGNORED_END
res = intern->document->handlers->dump_doc_to_str(docp, converted_options, (const char *) docp->encoding);
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
xmlSaveNoEmptyTags = old_xml_save_no_empty_tags;
ZEND_DIAGNOSTIC_IGNORED_END
}
if (!res) {

View File

@@ -1097,7 +1097,10 @@ static int dom_xml_serialize_element_node(
/* 14. If ns is the HTML namespace, and the node's list of children is empty, and the node's localName matches
* any one of the following void elements: ... */
if (element->children == NULL) {
if (xmlSaveNoEmptyTags) {
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
int saveNoEmptyTags = xmlSaveNoEmptyTags;
ZEND_DIAGNOSTIC_IGNORED_END
if (saveNoEmptyTags) {
/* Do nothing, use the <x></x> closing style. */
} else if (php_dom_ns_is_fast(element, php_dom_ns_is_html_magic_token)) {
size_t name_length = strlen((const char *) element->name);

View File

@@ -29,4 +29,4 @@ echo "msgf2: ", $msgf->format(array($time, 'date')), " ",
?>
--EXPECTF--
Deprecated: Calling IntlGregorianCalendar::__construct() with more than 2 arguments is deprecated, use either IntlGregorianCalendar::createFromDate() or IntlGregorianCalendar::createFromDateTime() instead in %s on line %d
quinta-feira, 17 de maio de 2012 5:35:36 da tarde ptlis
quinta-feira, 17 de maio de 2012 5:35:36 %r(da tarde|p.m.)%r ptlis

View File

@@ -19,12 +19,12 @@ var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_SHORT_COMMONLY_USED))
var_dump($lsb->getDisplayName(false, IntlTimeZone::DISPLAY_GENERIC_LOCATION));
?>
--EXPECT--
string(3) "GMT"
--EXPECTF--
string(%d) "%r(GMT|GMT\+0)%r"
string(30) "Western European Standard Time"
string(13) "Portugal Time"
string(21) "Western European Time"
string(5) "+0000"
string(3) "GMT"
string(3) "GMT"
string(%d) "%r(GMT|GMT\+00:00)%r"
string(%d) "%r(GMT|GMT\+0)%r"
string(13) "Portugal Time"

View File

@@ -813,9 +813,12 @@ is_string:
} else {
/* make stream not being closed when the zval is freed */
GC_ADDREF(stream->res);
ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
pib->context = stream;
pib->readcallback = php_libxml_streams_IO_read;
pib->closecallback = php_libxml_streams_IO_close;
ZEND_DIAGNOSTIC_IGNORED_END
ret = xmlNewIOInputStream(context, pib, enc);
if (ret == NULL) {

View File

@@ -300,6 +300,12 @@ safe:
}
plc->quoted = stmt->dbh->methods->quoter(stmt->dbh, buf, param_type);
if (plc->quoted == NULL) {
/* bork */
ret = -1;
strncpy(stmt->error_code, stmt->dbh->error_code, 6);
goto clean_up;
}
}
}

View File

@@ -0,0 +1,28 @@
--TEST--
#GHSA-8xr5-qppj-gvwj: NULL Pointer Derefernce for failed user input quoting
--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);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$sql = "SELECT * FROM users where username = :username";
$stmt = $db->prepare($sql);
$p1 = "alice\x99";
var_dump($stmt->execute(['username' => $p1]));
?>
--EXPECT--
bool(false)

View File

@@ -4272,7 +4272,7 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
uint32_t argc, i;
zval *src_entry;
HashTable *src, *dest;
uint32_t count = 0;
uint64_t count = 0;
ZEND_PARSE_PARAMETERS_START(0, -1)
Z_PARAM_VARIADIC('+', args, argc)
@@ -4292,6 +4292,11 @@ static zend_always_inline void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMET
count += zend_hash_num_elements(Z_ARRVAL_P(arg));
}
if (UNEXPECTED(count >= HT_MAX_SIZE)) {
zend_throw_error(NULL, "The total number of elements must be lower than %u", HT_MAX_SIZE);
RETURN_THROWS();
}
if (argc == 2) {
zval *ret = NULL;

View File

@@ -561,7 +561,7 @@ PHP_FUNCTION(inet_pton)
char buffer[17];
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(address, address_len)
Z_PARAM_PATH(address, address_len)
ZEND_PARSE_PARAMETERS_END();
memset(buffer, 0, sizeof(buffer));
@@ -593,7 +593,7 @@ PHP_FUNCTION(ip2long)
struct in_addr ip;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(addr, addr_len)
Z_PARAM_PATH(addr, addr_len)
ZEND_PARSE_PARAMETERS_END();
if (addr_len == 0 || inet_pton(AF_INET, addr, &ip) != 1) {
@@ -2139,8 +2139,8 @@ PHP_FUNCTION(getservbyname)
struct servent *serv;
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(name)
Z_PARAM_STRING(proto, proto_len)
Z_PARAM_PATH_STR(name)
Z_PARAM_PATH(proto, proto_len)
ZEND_PARSE_PARAMETERS_END();
@@ -2183,7 +2183,7 @@ PHP_FUNCTION(getservbyport)
ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_LONG(port)
Z_PARAM_STRING(proto, proto_len)
Z_PARAM_PATH(proto, proto_len)
ZEND_PARSE_PARAMETERS_END();
serv = getservbyport(htons((unsigned short) port), proto);
@@ -2210,7 +2210,7 @@ PHP_FUNCTION(getprotobyname)
struct protoent *ent;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(name, name_len)
Z_PARAM_PATH(name, name_len)
ZEND_PARSE_PARAMETERS_END();
ent = getprotobyname(name);

View File

@@ -382,7 +382,7 @@ PHP_FUNCTION(dns_check_record)
#endif
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STRING(hostname, hostname_len)
Z_PARAM_PATH(hostname, hostname_len)
Z_PARAM_OPTIONAL
Z_PARAM_STR(rectype)
ZEND_PARSE_PARAMETERS_END();
@@ -829,7 +829,7 @@ PHP_FUNCTION(dns_get_record)
bool raw = 0;
ZEND_PARSE_PARAMETERS_START(1, 5)
Z_PARAM_STRING(hostname, hostname_len)
Z_PARAM_PATH(hostname, hostname_len)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(type_param)
Z_PARAM_ZVAL(authns)
@@ -1067,7 +1067,7 @@ PHP_FUNCTION(dns_get_mx)
#endif
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STRING(hostname, hostname_len)
Z_PARAM_PATH(hostname, hostname_len)
Z_PARAM_ZVAL(mx_list)
Z_PARAM_OPTIONAL
Z_PARAM_ZVAL(weight_list)

View File

@@ -32,7 +32,7 @@ PHP_FUNCTION(dns_get_mx) /* {{{ */
DNS_STATUS status; /* Return value of DnsQuery_A() function */
PDNS_RECORD pResult, pRec; /* Pointer to DNS_RECORD structure */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "pz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) {
RETURN_THROWS();
}
@@ -86,7 +86,7 @@ PHP_FUNCTION(dns_check_record)
DNS_STATUS status; /* Return value of DnsQuery_A() function */
PDNS_RECORD pResult; /* Pointer to DNS_RECORD structure */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|S", &hostname, &hostname_len, &rectype) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|S", &hostname, &hostname_len, &rectype) == FAILURE) {
RETURN_THROWS();
}
@@ -343,7 +343,7 @@ PHP_FUNCTION(dns_get_record)
int type, type_to_fetch, first_query = 1, store_results = 1;
bool raw = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b",
if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|lz!z!b",
&hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) {
RETURN_THROWS();
}

View File

@@ -0,0 +1,16 @@
--TEST--
GHSA-h96m-rvf9-jgm2
--FILE--
<?php
$power = 20; // Chosen to be well within a memory_limit
$arr = range(0, 2**$power);
try {
array_merge(...array_fill(0, 2**(32-$power), $arr));
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF--
The total number of elements must be lower than %d

View File

@@ -0,0 +1,62 @@
--TEST--
GHSA-www2-q4fc-65wf
--DESCRIPTION--
This is a ZPP test but *keep* this as it is security-sensitive!
--FILE--
<?php
try {
dns_check_record("\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
dns_get_mx("\0", $out);
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
dns_get_record("\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
getprotobyname("\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
getservbyname("\0", "tcp");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
getservbyname("x", "tcp\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
getservbyport(0, "tcp\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
inet_pton("\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
try {
ip2long("\0");
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
dns_check_record(): Argument #1 ($hostname) must not contain any null bytes
dns_get_mx(): Argument #1 ($hostname) must not contain any null bytes
dns_get_record(): Argument #1 ($hostname) must not contain any null bytes
getprotobyname(): Argument #1 ($protocol) must not contain any null bytes
getservbyname(): Argument #1 ($service) must not contain any null bytes
getservbyname(): Argument #2 ($protocol) must not contain any null bytes
getservbyport(): Argument #2 ($protocol) must not contain any null bytes
inet_pton(): Argument #1 ($ip) must not contain any null bytes
ip2long(): Argument #1 ($ip) must not contain any null bytes