[SECURITY] XML entity expansion 27/46827/2
authorBenni Mack <benni@typo3.org>
Tue, 23 Feb 2016 10:44:20 +0000 (11:44 +0100)
committerOliver Hader <oliver.hader@typo3.org>
Tue, 23 Feb 2016 10:44:54 +0000 (11:44 +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: ed1cd758fafc81ed44f8f829ad3ed3a86c5db649
Security-Bulletins: TYPO3-CORE-SA-2016-005, 006, 007, 008
Change-Id: Ic5513ce257f0a6aa1a9cce7a617b59ed09341a78
Reviewed-on: https://review.typo3.org/46827
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
17 files changed:
typo3/sysext/adodb/adodb/adodb-xmlschema.inc.php
typo3/sysext/adodb/adodb/adodb-xmlschema03.inc.php
typo3/sysext/core/Classes/Localization/Parser/AbstractXmlParser.php
typo3/sysext/core/Classes/Localization/Parser/LocallangXmlParser.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/form/Classes/View/Confirmation/Element/AbstractElementView.php
typo3/sysext/form/Classes/View/Form/Element/AbstractElementView.php
typo3/sysext/form/Classes/View/Mail/Html/Element/AbstractElementView.php
typo3/sysext/lang/Classes/Utility/Connection/Ter.php
typo3/sysext/rtehtmlarea/Classes/Controller/SpellCheckingController.php
typo3/sysext/rtehtmlarea/Classes/Extension/MicroDataSchema.php
typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php

index 72a9f9b..4a86072 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..d39119d 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 ac4513c..fe9e9f0 100644 (file)
@@ -94,7 +94,11 @@ abstract class AbstractXmlParser implements \TYPO3\CMS\Core\Localization\Parser\
         * @throws \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException
         */
        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 \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file.', 1278155988);
                }
index ac18b6f..d08b333 100644 (file)
@@ -158,7 +158,11 @@ class LocallangXmlParser extends \TYPO3\CMS\Core\Localization\Parser\AbstractXml
        protected function parseXmlTargetFile($targetPath) {
                $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 \TYPO3\CMS\Core\Localization\Exception\InvalidXmlFileException('The path provided does not point to existing and accessible well-formed XML file (' . $targetPath . ').', 1278155987);
index 68a3ee1..a5f7f87 100755 (executable)
@@ -2015,12 +2015,15 @@ class GeneralUtility {
         * @author bisqwit at iki dot fi dot not dot for dot ads dot invalid / http://dk.php.net/xml_parse_into_struct + kasperYYYY@typo3.com
         */
        static public function xml2tree($string, $depth = 999) {
+               // 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();
                xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
                xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
                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));
                }
@@ -2256,6 +2259,8 @@ class GeneralUtility {
         * @see array2xml()
         */
        static protected 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();
@@ -2270,6 +2275,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 d6f6a53..e88e040 100644 (file)
@@ -263,7 +263,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 fe2499b..5605994 100644 (file)
@@ -239,7 +239,10 @@ class DocumentationService {
         * @return array Array representation of XML data
         */
        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 0e5868d..d418bb1 100644 (file)
@@ -68,6 +68,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);
@@ -82,6 +84,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), htmlspecialchars($file)), 1342640703);
                        }
                }
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                xml_parser_free($this->objXml);
        }
 
index e11433c..2430b20 100644 (file)
@@ -63,6 +63,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);
@@ -77,6 +79,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), htmlspecialchars($file)), 1342641011);
                        }
                }
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                xml_parser_free($this->objXml);
        }
 
index 836c9ce..cc3abc4 100644 (file)
@@ -101,6 +101,8 @@ abstract class AbstractGenerator {
         * @return \SimpleXMLElement the new element
         */
        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();
 
@@ -108,7 +110,10 @@ 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 c7f4195..64d1139 100644 (file)
@@ -167,12 +167,15 @@ abstract class AbstractElementView {
         * @return mixed \DOMDocument|\DOMNode XML part of the view object
         */
        public function render($type = 'element', $returnFirstChild = TRUE) {
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
                $useLayout = $this->getLayout((string) $type);
                $dom = new \DOMDocument('1.0', 'utf-8');
                $dom->formatOutput = TRUE;
                $dom->preserveWhiteSpace = FALSE;
                $dom->loadXML($useLayout);
                $emptyElement = $this->parseXML($dom, $dom);
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                if ($emptyElement) {
                        return NULL;
                } elseif ($returnFirstChild) {
index ee9a17a..ebff8a5 100644 (file)
@@ -213,12 +213,15 @@ abstract class AbstractElementView {
         * @return mixed \DOMDocument|\DOMNode XML part of the view object
         */
        public function render($type = 'element', $returnFirstChild = TRUE) {
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
                $useLayout = $this->getLayout((string) $type);
                $dom = new \DOMDocument('1.0', 'utf-8');
                $dom->formatOutput = TRUE;
                $dom->preserveWhiteSpace = FALSE;
                $dom->loadXML($useLayout);
                $this->parseXML($dom, $dom);
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                if ($returnFirstChild) {
                        return $dom->firstChild;
                } else {
index cbd5207..75d894a 100644 (file)
@@ -163,12 +163,15 @@ abstract class AbstractElementView {
         * @return \DOMDocument|\DOMNode XML part of the view object
         */
        public function render($type = 'element', $returnFirstChild = TRUE) {
+               // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+               $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
                $useLayout = $this->getLayout((string) $type);
                $dom = new \DOMDocument('1.0', 'utf-8');
                $dom->formatOutput = TRUE;
                $dom->preserveWhiteSpace = FALSE;
                $dom->loadXML($useLayout);
                $emptyElement = $this->parseXML($dom, $dom);
+               libxml_disable_entity_loader($previousValueOfEntityLoader);
                if ($emptyElement) {
                        return NULL;
                } elseif ($returnFirstChild) {
index 3e34cf0..f108ad9 100644 (file)
@@ -51,6 +51,8 @@ class Ter extends \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility {
        protected function parseL10nXML($string) {
                        // 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();
 
@@ -59,7 +61,7 @@ class Ter extends \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility {
 
                        // 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 e9f3c7f..4114f9d 100644 (file)
@@ -299,6 +299,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')) {
@@ -316,6 +318,7 @@ class SpellCheckingController {
                        if (xml_get_error_code($parser)) {
                                throw new \UnexpectedException('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 be97487..e974719 100644 (file)
@@ -124,9 +124,12 @@ class MicroDataSchema extends \TYPO3\CMS\Rtehtmlarea\RteHtmlAreaApi {
                $resources = array();
                $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 7ce7a87..030bacf 100644 (file)
@@ -72,8 +72,11 @@ class TypoScriptReferenceLoader {
         * @return void
         */
        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();
        }