Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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().
- Loading branch information
Showing
14 changed files
with
216 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
ext/dom/tests/libxml_global_state_entity_loader_bypass.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
--TEST-- | ||
GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) | ||
--SKIPIF-- | ||
<?php | ||
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'); | ||
?> | ||
--FILE-- | ||
<?php | ||
|
||
$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>"; | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
ext/simplexml/tests/libxml_global_state_entity_loader_bypass.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
--TEST-- | ||
GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) | ||
--SKIPIF-- | ||
<?php | ||
if (!extension_loaded('libxml')) die('skip libxml extension not available'); | ||
if (!extension_loaded('simplexml')) die('skip simplexml extension not available'); | ||
if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); | ||
?> | ||
--FILE-- | ||
<?php | ||
|
||
$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>"; | ||
|
||
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-- | ||
<?php | ||
@unlink("libxml_global_state_entity_loader_bypass.tmp"); | ||
?> | ||
--EXPECT-- | ||
--- String test --- | ||
--- Constructor test --- | ||
--- File test --- | ||
Done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
ext/xmlreader/tests/libxml_global_state_entity_loader_bypass.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--TEST-- | ||
GHSA-3qrf-m4j2-pcrr (libxml global state entity loader bypass) | ||
--SKIPIF-- | ||
<?php | ||
if (!extension_loaded('libxml')) die('skip libxml extension not available'); | ||
if (!extension_loaded('xmlreader')) die('skip xmlreader extension not available'); | ||
if (!extension_loaded('zend-test')) die('skip zend-test extension not available'); | ||
?> | ||
--FILE-- | ||
<?php | ||
|
||
$xml = "<?xml version='1.0'?><!DOCTYPE root [<!ENTITY % bork SYSTEM \"php://nope\"> %bork;]><nothing/>"; | ||
|
||
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-- | ||
<?php | ||
@unlink("libxml_global_state_entity_loader_bypass.tmp"); | ||
?> | ||
--EXPECT-- | ||
--- String test --- | ||
--- File test --- | ||
Done |
Oops, something went wrong.