[SECURITY] XML entity expansion 31/46831/2
authorBenni Mack <benni@typo3.org>
Tue, 23 Feb 2016 10:44:59 +0000 (11:44 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Tue, 23 Feb 2016 10:45:33 +0000 (11:45 +0100)
Remote XML entites can be loaded in places where TYPO3 expects
only local files to be fetched. All places are changed so
the option to load entities is disabled.

Resolves: #61269
Releases: master, 7.6, 6.2
Security-Commit: 982210fb34fc2f9848aa1c478e1fa439949cf746
Security-Bulletins: TYPO3-CORE-SA-2016-005, 006, 007, 008
Change-Id: I9b7c8b81a7cfb0b26092eb6053b69c88415bd46a
Reviewed-on: https://review.typo3.org/46831
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
18 files changed:
typo3/sysext/adodb/Documentation/Index.rst
typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php
typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php
typo3/sysext/core/Classes/Imaging/IconProvider/SvgIconProvider.php
typo3/sysext/core/Classes/Localization/Parser/AbstractXmlParser.php
typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.php
typo3/sysext/core/Classes/Type/File/ImageInfo.php
typo3/sysext/core/Classes/Utility/GeneralUtility.php
typo3/sysext/core/Tests/FunctionalTestCase.php
typo3/sysext/documentation/Classes/Service/DocumentationService.php
typo3/sysext/extensionmanager/Classes/Utility/Parser/ExtensionXmlPushParser.php
typo3/sysext/extensionmanager/Classes/Utility/Parser/MirrorXmlPushParser.php
typo3/sysext/fluid/Classes/Service/AbstractGenerator.php
typo3/sysext/lang/Classes/Service/TerService.php
typo3/sysext/recycler/Tests/Functional/Recycle/AbstractRecycleTestCase.php
typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php
typo3/sysext/rtehtmlarea/Classes/Extension/MicroDataSchema.php
typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php

index d1ef098..a3bae0d 100644 (file)
@@ -25,6 +25,7 @@ updated to upstream.
 - ADOdb: Allow setting NOT NULL/DEFAULT on blob and text columns (67442_) (Upstream pull request: [3]_)
 - ADOdb: Table names in sequences broken (64990_)
 - ADOdb: PHP7 redefinition of parameter (71244_)
+- Security: XML entity expansion (61269_)
 
 .. [2] https://github.com/ADOdb/ADOdb/commit/85f05a98974ea85ecae943faf230a27afdbaa746
 .. [3] https://github.com/ADOdb/ADOdb/pull/118
@@ -38,6 +39,7 @@ updated to upstream.
 .. _67442: https://forge.typo3.org/issues/67442
 .. _64990: https://forge.typo3.org/issues/64990
 .. _71244: https://forge.typo3.org/issues/71244
+.. _61269: https://forge.typo3.org/issues/61269
 
 
 Diff
index 72a9f9b..fc2c5bc 100644 (file)
@@ -1456,6 +1456,8 @@ class adoSchema {
                $this->success = 2;
 
                $xmlParser = $this->create_parser();
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
 
                // Process the file
                while( $data = fread( $fp, 4096 ) ) {
@@ -1468,6 +1470,7 @@ class adoSchema {
                        }
                }
 
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                xml_parser_free( $xmlParser );
 
                return $this->sqlArray;
@@ -1502,6 +1505,8 @@ class adoSchema {
                $this->success = 2;
 
                $xmlParser = $this->create_parser();
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
 
                if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
                        die( sprintf(
@@ -1511,6 +1516,7 @@ class adoSchema {
                        ) );
                }
 
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                xml_parser_free( $xmlParser );
 
                return $this->sqlArray;
index 3ed5aec..ba190e7 100644 (file)
@@ -1612,6 +1612,8 @@ class adoSchema {
                $this->success = 2;
 
                $xmlParser = $this->create_parser();
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
 
                // Process the file
                while( $data = fread( $fp, 4096 ) ) {
@@ -1624,6 +1626,7 @@ class adoSchema {
                        }
                }
 
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                xml_parser_free( $xmlParser );
 
                return $this->sqlArray;
@@ -1659,6 +1662,8 @@ class adoSchema {
                $this->success = 2;
 
                $xmlParser = $this->create_parser();
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
 
                if( !xml_parse( $xmlParser, $xmlstring, TRUE ) ) {
                        die( sprintf(
@@ -1668,6 +1673,7 @@ class adoSchema {
                        ) );
                }
 
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                xml_parser_free( $xmlParser );
 
                return $this->sqlArray;
index d4cf6f2..8e1e5e5 100644 (file)
@@ -93,7 +93,10 @@ class SvgIconProvider implements IconProviderInterface
 
         $svgContent = file_get_contents($source);
         $svgContent = preg_replace('/<script[\s\S]*?>[\s\S]*?<\/script>/i', '', $svgContent);
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $svgElement = simplexml_load_string($svgContent);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
 
         // remove xml version tag
         $domXml = dom_import_simplexml($svgElement);
index 947277c..fd00f6b 100644 (file)
@@ -101,7 +101,11 @@ abstract class AbstractXmlParser implements \TYPO3\CMS\Core\Localization\Parser\
      */
     protected function parseXmlFile()
     {
-        $rootXmlNode = simplexml_load_file($this->sourcePath, 'SimpleXMLElement', LIBXML_NOWARNING);
+        $xmlContent = file_get_contents($this->sourcePath);
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
+        $rootXmlNode = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOWARNING);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         if (!isset($rootXmlNode) || $rootXmlNode === false) {
             throw new InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file.', 1278155988);
         }
index 328c09c..d00f8be 100644 (file)
@@ -167,7 +167,11 @@ class LocallangXmlParser extends AbstractXmlParser
     {
         $rootXmlNode = false;
         if (file_exists($targetPath)) {
-            $rootXmlNode = simplexml_load_file($targetPath, 'SimpleXMLElement', LIBXML_NOWARNING);
+            $xmlContent = file_get_contents($targetPath);
+            // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+            $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
+            $rootXmlNode = simplexml_load_string($xmlContent, 'SimpleXMLElement', LIBXML_NOWARNING);
+            libxml_disable_entity_loader($previousValueOfEntityLoader);
         }
         if (!isset($rootXmlNode) || $rootXmlNode === false) {
             throw new InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file (' . $targetPath . ').', 1278155987);
index ef82186..faddaba 100644 (file)
@@ -86,7 +86,11 @@ class ImageInfo extends FileInfo
     {
         $imagesSizes = array();
 
-        $xml = simplexml_load_file($this->getPathname());
+        $fileContent = file_get_contents($this->getPathname());
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
+        $xml = simplexml_load_string($fileContent);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         $xmlAttributes = $xml->attributes();
 
         // First check if width+height are set
index 45948b1..1fb02f8 100755 (executable)
@@ -1986,6 +1986,8 @@ class GeneralUtility
      */
     public static function xml2tree($string, $depth = 999, $parserOptions = array())
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $parser = xml_parser_create();
         $vals = array();
         $index = array();
@@ -1995,6 +1997,7 @@ class GeneralUtility
             xml_parser_set_option($parser, $option, $value);
         }
         xml_parse_into_struct($parser, $string, $vals, $index);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         if (xml_get_error_code($parser)) {
             return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser));
         }
@@ -2234,6 +2237,8 @@ class GeneralUtility
      */
     protected static function xml2arrayProcess($string, $NSprefix = '', $reportDocTag = false)
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         // Create parser:
         $parser = xml_parser_create();
         $vals = array();
@@ -2248,6 +2253,7 @@ class GeneralUtility
         xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset);
         // Parse content:
         xml_parse_into_struct($parser, $string, $vals, $index);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         // If error, return error message:
         if (xml_get_error_code($parser)) {
             return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser));
index 1c62924..b5a26ec 100644 (file)
@@ -277,7 +277,11 @@ abstract class FunctionalTestCase extends BaseTestCase
 
         $database = $this->getDatabaseConnection();
 
-        $xml = simplexml_load_file($path);
+        $fileContent = file_get_contents($path);
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
+        $xml = simplexml_load_string($fileContent);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         $foreignKeys = array();
 
         /** @var $table \SimpleXMLElement */
index 75880d1..31fdc22 100644 (file)
@@ -245,7 +245,10 @@ class DocumentationService
      */
     protected function parsePackagesXML($string)
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $data = json_decode(json_encode((array)simplexml_load_string($string)), true);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         if (count($data) !== 2) {
             throw new \TYPO3\CMS\Documentation\Exception\XmlParser('Error in XML parser while decoding packages XML file.', 1374222437);
         }
index 68daf10..3a20d88 100644 (file)
@@ -69,6 +69,8 @@ class ExtensionXmlPushParser extends AbstractExtensionXmlParser
         if (!is_resource($this->objXml)) {
             throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342640663);
         }
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         // keep original character case of XML document
         xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, false);
         xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, false);
@@ -83,6 +85,7 @@ class ExtensionXmlPushParser extends AbstractExtensionXmlParser
                 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('XML error %s in line %u of file resource %s.', xml_error_string(xml_get_error_code($this->objXml)), xml_get_current_line_number($this->objXml), $file), 1342640703);
             }
         }
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         xml_parser_free($this->objXml);
     }
 
index f21b95b..3e77f43 100644 (file)
@@ -64,6 +64,8 @@ class MirrorXmlPushParser extends AbstractMirrorXmlParser
         if (!is_resource($this->objXml)) {
             throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException('Unable to create XML parser.', 1342641009);
         }
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         // keep original character case of XML document
         xml_parser_set_option($this->objXml, XML_OPTION_CASE_FOLDING, false);
         xml_parser_set_option($this->objXml, XML_OPTION_SKIP_WHITE, false);
@@ -78,6 +80,7 @@ class MirrorXmlPushParser extends AbstractMirrorXmlParser
                 throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(sprintf('XML error %s in line %u of file resource %s.', xml_error_string(xml_get_error_code($this->objXml)), xml_get_current_line_number($this->objXml), $file), 1342641011);
             }
         }
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         xml_parser_free($this->objXml);
     }
 
index 170185c..2406a3f 100644 (file)
@@ -105,6 +105,8 @@ abstract class AbstractGenerator
      */
     protected function addChildWithCData(\SimpleXMLElement $parentXmlNode, $childNodeName, $childNodeValue)
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $parentDomNode = dom_import_simplexml($parentXmlNode);
         $domDocument = new \DOMDocument();
 
@@ -112,6 +114,9 @@ abstract class AbstractGenerator
         $childNode->appendChild($domDocument->createCDATASection($childNodeValue));
         $childNodeTarget = $parentDomNode->ownerDocument->importNode($childNode, true);
         $parentDomNode->appendChild($childNodeTarget);
-        return simplexml_import_dom($childNodeTarget);
+        $returnValue = simplexml_import_dom($childNodeTarget);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
+
+        return $returnValue;
     }
 }
index 17dfcfa..840ee96 100644 (file)
@@ -54,12 +54,15 @@ class TerService extends \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtili
     {
         // Create parser:
         $parser = xml_parser_create();
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $values = array();
         $index = array();
         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
             // Parse content
         xml_parse_into_struct($parser, $string, $values, $index);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
             // If error, return error message
         if (xml_get_error_code($parser)) {
             $line = xml_get_current_line_number($parser);
index b197e0a..11eed51 100644 (file)
@@ -92,7 +92,11 @@ abstract class AbstractRecycleTestCase extends \TYPO3\CMS\Core\Tests\FunctionalT
         }
 
         $data = array();
-        $xml = simplexml_load_file($path);
+        $fileContent = file_get_contents($path);
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
+        $xml = simplexml_load_string($fileContent);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
 
         /** @var $table \SimpleXMLElement */
         foreach ($xml->children() as $table) {
index 1babffb..2fdc2aa 100644 (file)
@@ -316,6 +316,8 @@ class SpellCheckingController
             $content = GeneralUtility::_POST('content');
             // Parsing the input HTML
             $parser = xml_parser_create(strtoupper($this->parserCharset));
+            // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+            $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
             xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
             xml_set_object($parser, $this);
             if (!xml_set_element_handler($parser, 'startHandler', 'endHandler')) {
@@ -333,6 +335,7 @@ class SpellCheckingController
             if (xml_get_error_code($parser)) {
                 throw new \UnexpectedValueException('Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser)), 1294585788);
             }
+            libxml_disable_entity_loader($previousValueOfEntityLoader);
             xml_parser_free($parser);
             if ($this->pspell_is_available && !$this->forceCommandMode) {
                 pspell_clear_session($this->pspell_link);
index 547b114..e8f03d3 100644 (file)
@@ -107,9 +107,12 @@ class MicroDataSchema extends RteHtmlAreaApi
     {
         $types = array();
         $properties = array();
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         // Load the document
         $document = new \DOMDocument();
         $document->loadXML($string);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         if ($document) {
             // Scan resource descriptions
             $items = $document->getElementsByTagName('Description');
index 4b1f03c..7948aa0 100644 (file)
@@ -75,8 +75,11 @@ class TypoScriptReferenceLoader
      */
     protected function loadFile($filepath)
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $this->xmlDoc = new \DOMDocument('1.0', 'utf-8');
         $this->xmlDoc->load($filepath);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         // @TODO: oliver@typo3.org: I guess this is not required here
         $this->xmlDoc->saveXML();
     }