From d7de6908dfc8774e86a54100ad4e2ee810426001 Mon Sep 17 00:00:00 2001
From: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date: Sat, 15 Jul 2023 17:33:52 +0200
Subject: [PATCH 2/5] Sanitize libxml2 globals before parsing
Fixes GHSA-3qrf-m4j2-pcrr.
To parse a document with libxml2, you first need to create a parsing context.
The parsing context contains parsing options (e.g. XML_NOENT to substitute
entities) that the application (in this case PHP) can set.
Unfortunately, libxml2 also supports providing default set options.
For example, if you call xmlSubstituteEntitiesDefault(1) then the XML_NOENT
option will be added to the parsing options every time you create a parsing
context **even if the application never requested XML_NOENT**.
Third party extensions can override these globals, in particular the
substitute entity global. This causes entity substitution to be
unexpectedly active.
Fix it by setting the parsing options to a sane known value.
For API calls that depend on global state we introduce
PHP_LIBXML_SANITIZE_GLOBALS() and PHP_LIBXML_RESTORE_GLOBALS().
For other APIs that work directly with a context we introduce
php_libxml_sanitize_parse_ctxt_options().
(cherry picked from commit c283c3ab0ba45d21b2b8745c1f9c7cbfe771c975)
(cherry picked from commit b3758bd21223b97c042cae7bd26a66cde081ea98)
(cherry picked from commit 4fb61f06b1aff89a4d7e548c37ffa5bf573270c3)
---
ext/dom/document.c | 15 ++++++++
ext/dom/documentfragment.c | 2 ++
...xml_global_state_entity_loader_bypass.phpt | 36 +++++++++++++++++++
ext/libxml/php_libxml.h | 36 +++++++++++++++++++
ext/simplexml/simplexml.c | 6 ++++
...xml_global_state_entity_loader_bypass.phpt | 36 +++++++++++++++++++
ext/soap/php_xml.c | 2 ++
ext/xml/compat.c | 2 ++
ext/xmlreader/php_xmlreader.c | 9 +++++
...xml_global_state_entity_loader_bypass.phpt | 35 ++++++++++++++++++
ext/xsl/xsltprocessor.c | 9 +++--
11 files changed, 183 insertions(+), 5 deletions(-)
create mode 100644 ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
create mode 100644 ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
create mode 100644 ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
diff --git a/ext/dom/document.c b/ext/dom/document.c
index c212faa695..b0eed5820b 100644
--- a/ext/dom/document.c
+++ b/ext/dom/document.c
@@ -1438,6 +1438,7 @@ static xmlDocPtr dom_document_parser(zval *id, int mode, char *source, size_t so
options |= XML_PARSE_NOBLANKS;
}
+ php_libxml_sanitize_parse_ctxt_options(ctxt);
xmlCtxtUseOptions(ctxt, options);
ctxt->recovery = recover;
@@ -1735,7 +1736,9 @@ PHP_FUNCTION(dom_document_xinclude)
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
+ PHP_LIBXML_SANITIZE_GLOBALS(xinclude);
err = xmlXIncludeProcessFlags(docp, (int)flags);
+ PHP_LIBXML_RESTORE_GLOBALS(xinclude);
/* XML_XINCLUDE_START and XML_XINCLUDE_END nodes need to be removed as these
are added via xmlXIncludeProcess to mark beginning and ending of xincluded document
@@ -1774,6 +1777,7 @@ PHP_FUNCTION(dom_document_validate)
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
+ PHP_LIBXML_SANITIZE_GLOBALS(validate);
cvp = xmlNewValidCtxt();
cvp->userData = NULL;
@@ -1785,6 +1789,7 @@ PHP_FUNCTION(dom_document_validate)
} else {
RETVAL_FALSE;
}
+ PHP_LIBXML_RESTORE_GLOBALS(validate);
xmlFreeValidCtxt(cvp);
@@ -1818,14 +1823,18 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
DOM_GET_OBJ(docp, id, xmlDocPtr, intern);
+ PHP_LIBXML_SANITIZE_GLOBALS(new_parser_ctxt);
+
switch (type) {
case DOM_LOAD_FILE:
if (CHECK_NULL_PATH(source, source_len)) {
+ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
RETURN_FALSE;
}
valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN);
if (!valid_file) {
+ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
php_error_docref(NULL, E_WARNING, "Invalid Schema file source");
RETURN_FALSE;
}
@@ -1846,6 +1855,7 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
parser);
sptr = xmlSchemaParse(parser);
xmlSchemaFreeParserCtxt(parser);
+ PHP_LIBXML_RESTORE_GLOBALS(new_parser_ctxt);
if (!sptr) {
php_error_docref(NULL, E_WARNING, "Invalid Schema");
RETURN_FALSE;
@@ -1866,11 +1876,13 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
}
#endif
+ PHP_LIBXML_SANITIZE_GLOBALS(validate);
xmlSchemaSetValidOptions(vptr, valid_opts);
xmlSchemaSetValidErrors(vptr, php_libxml_error_handler, php_libxml_error_handler, vptr);
is_valid = xmlSchemaValidateDoc(vptr, docp);
xmlSchemaFree(sptr);
xmlSchemaFreeValidCtxt(vptr);
+ PHP_LIBXML_RESTORE_GLOBALS(validate);
if (is_valid == 0) {
RETURN_TRUE;
@@ -1940,12 +1952,14 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ
return;
}
+ PHP_LIBXML_SANITIZE_GLOBALS(parse);
xmlRelaxNGSetParserErrors(parser,
(xmlRelaxNGValidityErrorFunc) php_libxml_error_handler,
(xmlRelaxNGValidityWarningFunc) php_libxml_error_handler,
parser);
sptr = xmlRelaxNGParse(parser);
xmlRelaxNGFreeParserCtxt(parser);
+ PHP_LIBXML_RESTORE_GLOBALS(parse);
if (!sptr) {
php_error_docref(NULL, E_WARNING, "Invalid RelaxNG");
RETURN_FALSE;
@@ -2045,6 +2059,7 @@ static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
ctxt->sax->error = php_libxml_ctx_error;
ctxt->sax->warning = php_libxml_ctx_warning;
}
+ php_libxml_sanitize_parse_ctxt_options(ctxt);
if (options) {
htmlCtxtUseOptions(ctxt, (int)options);
}
diff --git a/ext/dom/documentfragment.c b/ext/dom/documentfragment.c
index 87cb691501..b7ecfdc14b 100644
--- a/ext/dom/documentfragment.c
+++ b/ext/dom/documentfragment.c
@@ -134,7 +134,9 @@ PHP_METHOD(domdocumentfragment, appendXML) {
}
if (data) {
+ PHP_LIBXML_SANITIZE_GLOBALS(parse);
err = xmlParseBalancedChunkMemory(nodep->doc, NULL, NULL, 0, (xmlChar *) data, &lst);
+ PHP_LIBXML_RESTORE_GLOBALS(parse);
if (err != 0) {
RETURN_FALSE;
}
diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
new file mode 100644
index 0000000000..b28afd4694
--- /dev/null
+++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -0,0 +1,36 @@
+--TEST--
+GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
+--SKIPIF--
+
+--FILE--
+ %bork;]>";
+
+libxml_use_internal_errors(true);
+
+function parseXML($xml) {
+ $doc = new DOMDocument();
+ @$doc->loadXML($xml);
+ $doc->createDocumentFragment()->appendXML("&bork;");
+ foreach (libxml_get_errors() as $error) {
+ var_dump(trim($error->message));
+ }
+}
+
+parseXML($xml);
+zend_test_override_libxml_global_state();
+parseXML($xml);
+
+echo "Done\n";
+
+?>
+--EXPECT--
+string(25) "Entity 'bork' not defined"
+string(25) "Entity 'bork' not defined"
+string(25) "Entity 'bork' not defined"
+Done
diff --git a/ext/libxml/php_libxml.h b/ext/libxml/php_libxml.h
index f7aa726d88..371b4eecc5 100644
--- a/ext/libxml/php_libxml.h
+++ b/ext/libxml/php_libxml.h
@@ -122,6 +122,42 @@ PHP_LIBXML_API void php_libxml_shutdown(void);
ZEND_TSRMLS_CACHE_EXTERN()
#endif
+/* Other extension may override the global state options, these global options
+ * are copied initially to ctxt->options. Set the options to a known good value.
+ * See libxml2 globals.c and parserInternals.c.
+ * The unique_name argument allows multiple sanitizes and restores within the
+ * same function, even nested is necessary. */
+#define PHP_LIBXML_SANITIZE_GLOBALS(unique_name) \
+ int xml_old_loadsubset_##unique_name = xmlLoadExtDtdDefaultValue; \
+ xmlLoadExtDtdDefaultValue = 0; \
+ int xml_old_validate_##unique_name = xmlDoValidityCheckingDefaultValue; \
+ xmlDoValidityCheckingDefaultValue = 0; \
+ int xml_old_pedantic_##unique_name = xmlPedanticParserDefault(0); \
+ int xml_old_substitute_##unique_name = xmlSubstituteEntitiesDefault(0); \
+ int xml_old_linenrs_##unique_name = xmlLineNumbersDefault(0); \
+ int xml_old_blanks_##unique_name = xmlKeepBlanksDefault(1);
+
+#define PHP_LIBXML_RESTORE_GLOBALS(unique_name) \
+ xmlLoadExtDtdDefaultValue = xml_old_loadsubset_##unique_name; \
+ xmlDoValidityCheckingDefaultValue = xml_old_validate_##unique_name; \
+ (void) xmlPedanticParserDefault(xml_old_pedantic_##unique_name); \
+ (void) xmlSubstituteEntitiesDefault(xml_old_substitute_##unique_name); \
+ (void) xmlLineNumbersDefault(xml_old_linenrs_##unique_name); \
+ (void) xmlKeepBlanksDefault(xml_old_blanks_##unique_name);
+
+/* Alternative for above, working directly on the context and not setting globals.
+ * Generally faster because no locking is involved, and this has the advantage that it sets the options to a known good value. */
+static zend_always_inline void php_libxml_sanitize_parse_ctxt_options(xmlParserCtxtPtr ctxt)
+{
+ ctxt->loadsubset = 0;
+ ctxt->validate = 0;
+ ctxt->pedantic = 0;
+ ctxt->replaceEntities = 0;
+ ctxt->linenumbers = 0;
+ ctxt->keepBlanks = 1;
+ ctxt->options = 0;
+}
+
#else /* HAVE_LIBXML */
#define libxml_module_ptr NULL
#endif
diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c
index 341daed0ee..c2b0230e19 100644
--- a/ext/simplexml/simplexml.c
+++ b/ext/simplexml/simplexml.c
@@ -2217,7 +2217,9 @@ PHP_FUNCTION(simplexml_load_file)
RETURN_FALSE;
}
+ PHP_LIBXML_SANITIZE_GLOBALS(read_file);
docp = xmlReadFile(filename, NULL, (int)options);
+ PHP_LIBXML_RESTORE_GLOBALS(read_file);
if (!docp) {
RETURN_FALSE;
@@ -2271,7 +2273,9 @@ PHP_FUNCTION(simplexml_load_string)
RETURN_FALSE;
}
+ PHP_LIBXML_SANITIZE_GLOBALS(read_memory);
docp = xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
+ PHP_LIBXML_RESTORE_GLOBALS(read_memory);
if (!docp) {
RETURN_FALSE;
@@ -2321,7 +2325,9 @@ SXE_METHOD(__construct)
return;
}
+ PHP_LIBXML_SANITIZE_GLOBALS(read_file_or_memory);
docp = is_url ? xmlReadFile(data, NULL, (int)options) : xmlReadMemory(data, (int)data_len, NULL, NULL, (int)options);
+ PHP_LIBXML_RESTORE_GLOBALS(read_file_or_memory);
if (!docp) {
((php_libxml_node_object *)sxe)->document = NULL;
diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
new file mode 100644
index 0000000000..2152e01232
--- /dev/null
+++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -0,0 +1,36 @@
+--TEST--
+GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
+--SKIPIF--
+
+--FILE--
+ %bork;]>";
+
+libxml_use_internal_errors(true);
+zend_test_override_libxml_global_state();
+
+echo "--- String test ---\n";
+simplexml_load_string($xml);
+echo "--- Constructor test ---\n";
+new SimpleXMLElement($xml);
+echo "--- File test ---\n";
+file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml);
+simplexml_load_file("libxml_global_state_entity_loader_bypass.tmp");
+
+echo "Done\n";
+
+?>
+--CLEAN--
+
+--EXPECT--
+--- String test ---
+--- Constructor test ---
+--- File test ---
+Done
diff --git a/ext/soap/php_xml.c b/ext/soap/php_xml.c
index 1ac684eb81..053960c559 100644
--- a/ext/soap/php_xml.c
+++ b/ext/soap/php_xml.c
@@ -94,6 +94,7 @@ xmlDocPtr soap_xmlParseFile(const char *filename)
if (ctxt) {
zend_bool old;
+ php_libxml_sanitize_parse_ctxt_options(ctxt);
ctxt->keepBlanks = 0;
ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
ctxt->sax->comment = soap_Comment;
@@ -144,6 +145,7 @@ xmlDocPtr soap_xmlParseMemory(const void *buf, size_t buf_size)
if (ctxt) {
zend_bool old;
+ php_libxml_sanitize_parse_ctxt_options(ctxt);
ctxt->sax->ignorableWhitespace = soap_ignorableWhitespace;
ctxt->sax->comment = soap_Comment;
ctxt->sax->warning = NULL;
diff --git a/ext/xml/compat.c b/ext/xml/compat.c
index ef83485722..c55047215b 100644
--- a/ext/xml/compat.c
+++ b/ext/xml/compat.c
@@ -19,6 +19,7 @@
#include "php.h"
#if defined(HAVE_LIBXML) && (defined(HAVE_XML) || defined(HAVE_XMLRPC)) && !defined(HAVE_LIBEXPAT)
#include "expat_compat.h"
+#include "ext/libxml/php_libxml.h"
typedef struct _php_xml_ns {
xmlNsPtr nsptr;
@@ -473,6 +474,7 @@ XML_ParserCreate_MM(const XML_Char *encoding, const XML_Memory_Handling_Suite *m
parser->parser->charset = XML_CHAR_ENCODING_NONE;
#endif
+ php_libxml_sanitize_parse_ctxt_options(parser->parser);
#if LIBXML_VERSION >= 20703
xmlCtxtUseOptions(parser->parser, XML_PARSE_OLDSAX);
#endif
diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c
index 0f2b62ae20..f0fd013ff9 100644
--- a/ext/xmlreader/php_xmlreader.c
+++ b/ext/xmlreader/php_xmlreader.c
@@ -301,6 +301,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz
return NULL;
}
+ PHP_LIBXML_SANITIZE_GLOBALS(parse);
if (error_func || warn_func) {
xmlRelaxNGSetParserErrors(parser,
(xmlRelaxNGValidityErrorFunc) error_func,
@@ -309,6 +310,7 @@ static xmlRelaxNGPtr _xmlreader_get_relaxNG(char *source, size_t source_len, siz
}
sptr = xmlRelaxNGParse(parser);
xmlRelaxNGFreeParserCtxt(parser);
+ PHP_LIBXML_RESTORE_GLOBALS(parse);
return sptr;
}
@@ -881,7 +883,9 @@ PHP_METHOD(xmlreader, open)
valid_file = _xmlreader_get_valid_file_path(source, resolved_path, MAXPATHLEN );
if (valid_file) {
+ PHP_LIBXML_SANITIZE_GLOBALS(reader_for_file);
reader = xmlReaderForFile(valid_file, encoding, options);
+ PHP_LIBXML_RESTORE_GLOBALS(reader_for_file);
}
if (reader == NULL) {
@@ -959,7 +963,9 @@ PHP_METHOD(xmlreader, setSchema)
intern = Z_XMLREADER_P(id);
if (intern && intern->ptr) {
+ PHP_LIBXML_SANITIZE_GLOBALS(schema);
retval = xmlTextReaderSchemaValidate(intern->ptr, source);
+ PHP_LIBXML_RESTORE_GLOBALS(schema);
if (retval == 0) {
RETURN_TRUE;
@@ -1079,6 +1085,7 @@ PHP_METHOD(xmlreader, XML)
}
uri = (char *) xmlCanonicPath((const xmlChar *) resolved_path);
}
+ PHP_LIBXML_SANITIZE_GLOBALS(text_reader);
reader = xmlNewTextReader(inputbfr, uri);
if (reader != NULL) {
@@ -1099,9 +1106,11 @@ PHP_METHOD(xmlreader, XML)
xmlFree(uri);
}
+ PHP_LIBXML_RESTORE_GLOBALS(text_reader);
return;
}
}
+ PHP_LIBXML_RESTORE_GLOBALS(text_reader);
}
if (uri) {
diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
new file mode 100644
index 0000000000..e9ffb04c2b
--- /dev/null
+++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -0,0 +1,35 @@
+--TEST--
+GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
+--SKIPIF--
+
+--FILE--
+ %bork;]>";
+
+libxml_use_internal_errors(true);
+zend_test_override_libxml_global_state();
+
+echo "--- String test ---\n";
+$reader = XMLReader::xml($xml);
+$reader->read();
+echo "--- File test ---\n";
+file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml);
+$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp");
+$reader->read();
+
+echo "Done\n";
+
+?>
+--CLEAN--
+
+--EXPECT--
+--- String test ---
+--- File test ---
+Done
diff --git a/ext/xsl/xsltprocessor.c b/ext/xsl/xsltprocessor.c
index 9948d6f0b3..7bbe640a5c 100644
--- a/ext/xsl/xsltprocessor.c
+++ b/ext/xsl/xsltprocessor.c
@@ -396,7 +396,7 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
xmlDoc *doc = NULL, *newdoc = NULL;
xsltStylesheetPtr sheetp, oldsheetp;
xsl_object *intern;
- int prevSubstValue, prevExtDtdValue, clone_docu = 0;
+ int clone_docu = 0;
xmlNode *nodep = NULL;
zend_object_handlers *std_hnd;
zval *cloneDocu, member, rv;
@@ -419,13 +419,12 @@ PHP_FUNCTION(xsl_xsltprocessor_import_stylesheet)
stylesheet document otherwise the node proxies will be a mess */
newdoc = xmlCopyDoc(doc, 1);
xmlNodeSetBase((xmlNodePtr) newdoc, (xmlChar *)doc->URL);
- prevSubstValue = xmlSubstituteEntitiesDefault(1);
- prevExtDtdValue = xmlLoadExtDtdDefaultValue;
+ PHP_LIBXML_SANITIZE_GLOBALS(parse);
+ xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
sheetp = xsltParseStylesheetDoc(newdoc);
- xmlSubstituteEntitiesDefault(prevSubstValue);
- xmlLoadExtDtdDefaultValue = prevExtDtdValue;
+ PHP_LIBXML_RESTORE_GLOBALS(parse);
if (!sheetp) {
xmlFreeDoc(newdoc);
--
2.41.0
From 3535016313ece1e12ffd5d9fc2f39478941be3d8 Mon Sep 17 00:00:00 2001
From: Remi Collet
Date: Tue, 1 Aug 2023 07:37:25 +0200
Subject: [PATCH 3/5] backport zend_test changes
(zend_test_override_libxml_global_state)
(cherry picked from commit 24e669e790e6aebd219c9a9fa19017455c8646b4)
(cherry picked from commit 79a97d0e2b93c40c3728d587046266989c5acc42)
---
...xml_global_state_entity_loader_bypass.phpt | 1 +
...xml_global_state_entity_loader_bypass.phpt | 1 +
...xml_global_state_entity_loader_bypass.phpt | 5 +++--
ext/zend_test/test.c | 22 +++++++++++++++++++
4 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
index b28afd4694..7fc2a249ac 100644
--- a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -5,6 +5,7 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
if (!extension_loaded('libxml')) die('skip libxml extension not available');
if (!extension_loaded('dom')) die('skip dom extension not available');
if (!extension_loaded('zend-test')) die('skip zend-test extension not available');
+if (!function_exists('zend_test_override_libxml_global_state')) die('skip not for Windows');
?>
--FILE--
--FILE--
--FILE--
read();
echo "--- File test ---\n";
file_put_contents("libxml_global_state_entity_loader_bypass.tmp", $xml);
-$reader = XMLReader::open("libxml_global_state_entity_loader_bypass.tmp");
+$reader = @XMLReader::open("libxml_global_state_entity_loader_bypass.tmp");
$reader->read();
echo "Done\n";
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index 4a7fe540fb..611bc9b68c 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -25,6 +25,11 @@
#include "ext/standard/info.h"
#include "php_test.h"
+#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
+# include
+# include
+#endif
+
static zend_class_entry *zend_test_interface;
static zend_class_entry *zend_test_class;
static zend_class_entry *zend_test_trait;
@@ -44,6 +49,20 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_leak_variable, 0, 0, 1)
ZEND_ARG_INFO(0, variable)
ZEND_END_ARG_INFO()
+#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
+static ZEND_FUNCTION(zend_test_override_libxml_global_state)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ xmlLoadExtDtdDefaultValue = 1;
+ xmlDoValidityCheckingDefaultValue = 1;
+ (void) xmlPedanticParserDefault(1);
+ (void) xmlSubstituteEntitiesDefault(1);
+ (void) xmlLineNumbersDefault(1);
+ (void) xmlKeepBlanksDefault(0);
+}
+#endif
+
ZEND_FUNCTION(zend_test_func)
{
/* dummy */
@@ -251,6 +270,9 @@ const zend_function_entry zend_test_functions[] = {
ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string)
ZEND_FE(zend_leak_bytes, NULL)
ZEND_FE(zend_leak_variable, arginfo_zend_leak_variable)
+#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
+ ZEND_FE(zend_test_override_libxml_global_state, NULL)
+#endif
ZEND_FE_END
};
--
2.41.0
From 26d70866843598f4a2ed94b01999b38e1d7c0e97 Mon Sep 17 00:00:00 2001
From: Remi Collet
Date: Tue, 1 Aug 2023 15:45:24 +0200
Subject: [PATCH 4/5] adapt to 7.2
---
ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt | 1 -
.../tests/libxml_global_state_entity_loader_bypass.phpt | 1 -
.../tests/libxml_global_state_entity_loader_bypass.phpt | 1 -
ext/zend_test/test.c | 2 --
4 files changed, 5 deletions(-)
diff --git a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
index 7fc2a249ac..25499006d9 100644
--- a/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
+++ b/ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -4,7 +4,6 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
--FILE--
diff --git a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
index 54f9d4941e..e09ecb5d72 100644
--- a/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
+++ b/ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -4,7 +4,6 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
--FILE--
diff --git a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
index b0120b325e..9824e10603 100644
--- a/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
+++ b/ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
@@ -4,7 +4,6 @@ GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass)
--FILE--
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index 611bc9b68c..51818083d9 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -52,8 +52,6 @@ ZEND_END_ARG_INFO()
#if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
static ZEND_FUNCTION(zend_test_override_libxml_global_state)
{
- ZEND_PARSE_PARAMETERS_NONE();
-
xmlLoadExtDtdDefaultValue = 1;
xmlDoValidityCheckingDefaultValue = 1;
(void) xmlPedanticParserDefault(1);
--
2.41.0
From 79c0bf87711036b83f8ee1723c034ccc839d847b Mon Sep 17 00:00:00 2001
From: Remi Collet
Date: Tue, 1 Aug 2023 07:22:33 +0200
Subject: [PATCH 5/5] NEWS
(cherry picked from commit ef1d507acf7be23d7624dc3c891683b2218feb51)
(cherry picked from commit 3cf7c2b10e577136b267f2d90bfdff6743271c5c)
---
NEWS | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/NEWS b/NEWS
index 5f49a7ee04..286f3df0f4 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,16 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+Backported from 8.0.30
+
+- Libxml:
+ . Fixed bug GHSA-3qrf-m4j2-pcrr (Security issue with external entity loading
+ in XML without enabling it). (CVE-2023-3823) (nielsdos, ilutov)
+
+- Phar:
+ . Fixed bug GHSA-jqcx-ccgc-xwhv (Buffer mismanagement in phar_dir_read()).
+ (CVE-2023-3824) (nielsdos)
+
Backported from 8.0.29
- Soap:
--
2.41.0