Skip to content
Merged
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ PHP NEWS
. Fixed Dom\DtdNamedNodeMap integer dimension access so negative indexes
return NULL and indexes outside the int range throw ValueError instead of
returning the first entity or notation. (Weilin Du)
. Fixed bug GH-22623 (use after free with namespace nodes from
XSLTProcessor::registerFunctions())/ (David Carlier)

- Exif:
. Fixed bug GH-11020 (exif_read_data() emits a spurious "Illegal IFD size"
Expand Down Expand Up @@ -80,6 +82,8 @@ PHP NEWS
- Standard:
. Fixed sleep() and usleep() to reject values that overflow the underlying
unsigned int timeout. (Weilin Du)
. Fixed bug GH-22671 (assert.bail aborts the process when the assert callback
throws an exception whose reporting re-throws). (iliaal)

- Streams:
. Fixed bug GH-21468 (Segfault in file_get_contents w/ a https URL
Expand Down
11 changes: 11 additions & 0 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -6071,6 +6071,17 @@ static zval *date_period_get_property_ptr_ptr(zend_object *object, zend_string *

static HashTable *date_period_get_properties_for(zend_object *object, zend_prop_purpose purpose)
{
if (purpose == ZEND_PROP_PURPOSE_DEBUG) {
if (object->ce->__debugInfo) {
int is_temp = 0;
HashTable *ht = zend_std_get_debug_info(object, &is_temp);
if (ht && !is_temp) {
GC_TRY_ADDREF(ht);
}
return ht;
}
}

php_period_obj *period_obj = php_period_obj_from_obj(object);
HashTable *props = zend_array_dup(zend_std_get_properties(object));
if (!period_obj->initialized) {
Expand Down
6 changes: 3 additions & 3 deletions ext/dom/xpath_callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,15 +347,15 @@ static zval *php_dom_xpath_callback_fetch_args(xmlXPathParserContextPtr ctxt, ui
xmlNodePtr node = obj->nodesetval->nodeTab[j];
zval child;
if (UNEXPECTED(node->type == XML_NAMESPACE_DECL)) {
xmlNodePtr nsparent = node->_private;
xmlNsPtr original = (xmlNsPtr) node;

/* Make sure parent dom object exists, so we can take an extra reference. */
zval parent_zval; /* don't destroy me, my lifetime is transferred to the fake namespace decl */
php_dom_create_object(nsparent, &parent_zval, intern);
proxy_factory(node->_private, &parent_zval, intern, ctxt);
dom_object *parent_intern = Z_DOMOBJ_P(&parent_zval);
xmlNodePtr parent = dom_object_get_node(parent_intern);

php_dom_create_fake_namespace_decl(nsparent, original, &child, parent_intern);
php_dom_create_fake_namespace_decl(parent, original, &child, parent_intern);
} else {
proxy_factory(node, &child, intern, ctxt);
}
Expand Down
14 changes: 14 additions & 0 deletions ext/reflection/tests/ReflectionConstant_null_byte_value.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
--TEST--
GH-22658: ReflectionConstant with a string value with a null byte
--FILE--
<?php

define('DEMO', "f\0oo");
$r = new ReflectionConstant('DEMO');
echo $r;
var_dump( $r->getValue() );

?>
--EXPECTF--
Constant [ string DEMO ] { f%0oo }
string(4) "f%0oo"
4 changes: 3 additions & 1 deletion ext/standard/assert.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,9 @@ PHP_FUNCTION(assert)
* exception so we can avoid bailout and use unwind_exit. */
zend_exception_error(EG(exception), E_WARNING);
}
zend_throw_unwind_exit();
if (!EG(exception)) {
zend_throw_unwind_exit();
}
RETURN_THROWS();
} else {
RETURN_FALSE;
Expand Down
40 changes: 40 additions & 0 deletions ext/standard/tests/assert/gh22671.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
GH-22671 (assert.bail must not call zend_throw_unwind_exit with a pending exception)
--INI--
zend.assertions=1
assert.bail=1
assert.exception=0
assert.callback=cb
error_reporting=0
--FILE--
<?php
register_shutdown_function(function () {
echo "shutdown reached\n";
});

class Inner extends Exception {
public function __destruct() {
throw new Exception("thrown from __destruct");
}
}

class Boom extends Exception {
public function __toString(): string {
throw new Inner("inner");
}
}

function cb() {
throw new Boom("boom");
}

// The callback throws Boom; the bail path prints it, which re-throws from
// Boom::__toString(), and releasing that exception re-throws again from
// Inner::__destruct(). The bail path must not reach zend_throw_unwind_exit()
// while an exception is pending, otherwise the process aborts.
assert(false);

echo "not reached\n";
?>
--EXPECT--
shutdown reached
63 changes: 63 additions & 0 deletions ext/xsl/tests/gh22621.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
--TEST--
GH-22621 (UAF via XSLTProcessor::registerPHPFunctions() retaining namespace nodes from an external document)
--EXTENSIONS--
dom
xsl
--CREDITS--
ExPatch-LLC
--FILE--
<?php
$cDIR = __DIR__;
file_put_contents($cDIR . '/gh22621_external.xml', '<root xmlns:custom="urn:custom"><data>secret</data></root>');
$uri = 'file:///' . ltrim(str_replace('\\', '/', $cDIR), '/') . '/gh22621_external.xml';

$stored_ns = null;

function capture_ns($nodes) {
global $stored_ns;
foreach ($nodes as $node) {
if ($node instanceof DOMNameSpaceNode) {
$stored_ns = $node;
}
}
return "captured";
}

$xsl = new DOMDocument();
$xsl->loadXML(<<<XSL
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:php="http://php.net/xsl">
<xsl:template match="/">
<result>
<xsl:value-of select="php:function('capture_ns', document('$uri')/*/namespace::*)"/>
</result>
</xsl:template>
</xsl:stylesheet>
XSL);

$doc = new DOMDocument();
$doc->loadXML('<input/>');

$proc = new XSLTProcessor();
$proc->registerPHPFunctions();
$proc->importStylesheet($xsl);
echo $proc->transformToXml($doc);

var_dump($stored_ns->localName);
var_dump($stored_ns->namespaceURI);
var_dump($stored_ns->parentNode->localName);
var_dump($stored_ns->ownerDocument instanceof DOMDocument);
?>
--CLEAN--
<?php
@unlink(__DIR__ . '/gh22621_external.xml');
?>
--EXPECTF--
<?xml version="1.0"?>
<result xmlns:php="http://php.net/xsl">captured</result>
string(6) "custom"
string(10) "urn:custom"
string(4) "root"
bool(true)