[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#782147: marked as done (unblock: mediawiki/1:1.19.20+dfsg-2.3)



Your message dated Wed, 08 Apr 2015 17:08:41 +0200
with message-id <55254479.9060104@thykier.net>
and subject line Re: Bug#782147: unblock: mediawiki/1:1.19.20+dfsg-2.3
has caused the Debian Bug report #782147,
regarding unblock: mediawiki/1:1.19.20+dfsg-2.3
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
782147: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=782147
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Please unblock package mediawiki.

The only change is an addition of an upstream patch for this release branch
which fixes a number of security issues.

unblock mediawiki/1:1.19.20+dfsg-2.3

Thanks,
Thijs
diff -Nru mediawiki-1.19.20+dfsg/debian/changelog mediawiki-1.19.20+dfsg/debian/changelog
--- mediawiki-1.19.20+dfsg/debian/changelog	2014-12-21 12:11:10.000000000 +0000
+++ mediawiki-1.19.20+dfsg/debian/changelog	2015-04-06 16:55:57.000000000 +0000
@@ -1,3 +1,21 @@
+mediawiki (1:1.19.20+dfsg-2.3) unstable; urgency=high
+
+  * Non-maintainer upload.
+  * Add patch fixing several security issues:
+    - (bug T85848, bug T71210) SECURITY: Don't parse XMP blocks that
+       contain XML entities, to prevent various DoS attacks.
+    - (bug T88310) SECURITY: Always expand xml entities when checking
+      SVG's.
+    - (bug T73394) SECURITY: Escape > in Html::expandAttributes to
+      prevent XSS.
+    - (bug T85855) SECURITY: Don't execute another user's CSS or JS
+      on preview.
+    - (bug T85349, bug T85850, bug T86711) SECURITY: Multiple issues
+      fixed in SVG filtering to prevent XSS and protect viewer's
+      privacy.
+
+ -- Thijs Kinkhorst <thijs@debian.org>  Mon, 06 Apr 2015 16:53:54 +0000
+
 mediawiki (1:1.19.20+dfsg-2.2) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru mediawiki-1.19.20+dfsg/debian/patches/security_1.19.24.patch mediawiki-1.19.20+dfsg/debian/patches/security_1.19.24.patch
--- mediawiki-1.19.20+dfsg/debian/patches/security_1.19.24.patch	1970-01-01 00:00:00.000000000 +0000
+++ mediawiki-1.19.20+dfsg/debian/patches/security_1.19.24.patch	2015-04-06 17:03:41.000000000 +0000
@@ -0,0 +1,636 @@
+From: Mediawiki
+Subject: Fix security issues as fixed in upstream security fix release 1.19.24:
+(bug T85848, bug T71210) SECURITY: Don't parse XMP blocks that contain XML entities, to prevent various DoS attacks.
+(bug T88310) SECURITY: Always expand xml entities when checking SVG's.
+(bug T73394) SECURITY: Escape > in Html::expandAttributes to prevent XSS.
+(bug T85855) SECURITY: Don't execute another user's CSS or JS on preview.
+(bug T85349, bug T85850, bug T86711) SECURITY: Multiple issues fixed in SVG filtering to prevent XSS and protect viewer's privacy.
+Origin: upstream, https://lists.wikimedia.org/pipermail/mediawiki-announce/2015-March/000175.html
+
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/EditPage.php mediawiki-1.19.24/includes/EditPage.php
+--- mediawiki-1.19.23/includes/EditPage.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/EditPage.php	2015-03-31 13:23:38.000000000 +0000
+@@ -1988,14 +1988,19 @@
+ 				if ( $this->isWrongCaseCssJsPage ) {
+ 					$wgOut->wrapWikiMsg( "<div class='error' id='mw-userinvalidcssjstitle'>\n$1\n</div>", array( 'userinvalidcssjstitle', $this->mTitle->getSkinFromCssJsSubpage() ) );
+ 				}
++				if ( $this->getTitle()->isSubpageOf( $wgUser->getUserPage() ) ) {
+ 				if ( $this->formtype !== 'preview' ) {
+-					if ( $this->isCssSubpage )
++						if ( $this->isCssSubpage ) {
+ 						$wgOut->wrapWikiMsg( "<div id='mw-usercssyoucanpreview'>\n$1\n</div>", array( 'usercssyoucanpreview' ) );
+-					if ( $this->isJsSubpage )
++						}
++
++						if ( $this->isJsSubpage ) {
+ 						$wgOut->wrapWikiMsg( "<div id='mw-userjsyoucanpreview'>\n$1\n</div>", array( 'userjsyoucanpreview' ) );
+ 				}
+ 			}
+ 		}
++			}
++		}
+ 
+ 		if ( $this->mTitle->getNamespace() != NS_MEDIAWIKI && $this->mTitle->isProtected( 'edit' ) ) {
+ 			# Is the title semi-protected?
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/Html.php mediawiki-1.19.24/includes/Html.php
+--- mediawiki-1.19.23/includes/Html.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/Html.php	2015-03-31 13:23:38.000000000 +0000
+@@ -525,17 +525,20 @@
+ 			} else {
+ 				# Apparently we need to entity-encode \n, \r, \t, although the
+ 				# spec doesn't mention that.  Since we're doing strtr() anyway,
+-				# and we don't need <> escaped here, we may as well not call
+-				# htmlspecialchars().
++				# we may as well not call htmlspecialchars().
+ 				# @todo FIXME: Verify that we actually need to
+ 				# escape \n\r\t here, and explain why, exactly.
+ 				#
+ 				# We could call Sanitizer::encodeAttribute() for this, but we
+ 				# don't because we're stubborn and like our marginal savings on
+ 				# byte size from not having to encode unnecessary quotes.
++				# The only difference between this transform and the one by
++				# Sanitizer::encodeAttribute() is '<' is only encoded here if
++				# $wgWellFormedXml is set, and ' is not encoded.
+ 				$map = array(
+ 					'&' => '&amp;',
+ 					'"' => '&quot;',
++					'>' => '&gt;',
+ 					"\n" => '&#10;',
+ 					"\r" => '&#13;',
+ 					"\t" => '&#9;'
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/media/BitmapMetadataHandler.php mediawiki-1.19.24/includes/media/BitmapMetadataHandler.php
+--- mediawiki-1.19.23/includes/media/BitmapMetadataHandler.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/media/BitmapMetadataHandler.php	2015-03-31 13:23:38.000000000 +0000
+@@ -126,7 +126,7 @@
+ 	 * @throws MWException on invalid file.
+ 	 */
+ 	static function Jpeg ( $filename ) {
+-		$showXMP = function_exists( 'xml_parser_create_ns' );
++		$showXMP = XMPReader::isSupported();
+ 		$meta = new self();
+ 
+ 		$seg = JpegMetadataExtractor::segmentSplitter( $filename );
+@@ -168,7 +168,7 @@
+ 	 * @return Array Array for storage in img_metadata.
+ 	 */
+ 	static public function PNG ( $filename ) {
+-		$showXMP = function_exists( 'xml_parser_create_ns' );
++		$showXMP = XMPReader::isSupported();
+ 
+ 		$meta = new self();
+ 		$array = PNGMetadataExtractor::getMetadata( $filename );
+@@ -205,7 +205,7 @@
+ 			$meta->addMetadata( array( 'GIFFileComment' => $baseArray['comment'] ), 'native' );
+ 		}
+ 
+-		if ( $baseArray['xmp'] !== '' && function_exists( 'xml_parser_create_ns' ) ) {
++		if ( $baseArray['xmp'] !== '' && XMPReader::isSupported() ) {
+ 			$xmp = new XMPReader();
+ 			$xmp->parse( $baseArray['xmp'] );
+ 			$xmpRes = $xmp->getResults();
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/media/JpegMetadataExtractor.php mediawiki-1.19.24/includes/media/JpegMetadataExtractor.php
+--- mediawiki-1.19.23/includes/media/JpegMetadataExtractor.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/media/JpegMetadataExtractor.php	2015-03-31 13:23:38.000000000 +0000
+@@ -24,7 +24,7 @@
+ 	* @throws MWException if given invalid file.
+ 	*/
+ 	static function segmentSplitter ( $filename ) {
+-		$showXMP = function_exists( 'xml_parser_create_ns' );
++		$showXMP = XMPReader::isSupported();
+ 
+ 		$segmentCount = 0;
+ 
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/media/XMP.php mediawiki-1.19.24/includes/media/XMP.php
+--- mediawiki-1.19.23/includes/media/XMP.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/media/XMP.php	2015-03-31 13:23:38.000000000 +0000
+@@ -40,6 +40,12 @@
+ 
+ 	protected $items;
+ 
++	/** @var int Flag determining if the XMP is safe to parse **/
++	private $parsable = 0;
++
++	/** @var string Buffer of XML to parse **/
++	private $xmlParsableBuffer = '';
++
+ 	/**
+ 	* These are various mode constants.
+ 	* they are used to figure out what to do
+@@ -69,6 +75,12 @@
+ 	const NS_XML = 'http://www.w3.org/XML/1998/namespace';
+ 
+ 
++	// States used while determining if XML is safe to parse
++	const PARSABLE_UNKNOWN = 0;
++	const PARSABLE_OK = 1;
++	const PARSABLE_BUFFERING = 2;
++	const PARSABLE_NO = 3;
++
+ 	/**
+ 	* Constructor.
+ 	*
+@@ -106,6 +118,9 @@
+ 			array( $this, 'endElement' ) );
+ 
+ 		xml_set_character_data_handler( $this->xmlParser, array( $this, 'char' ) );
++
++		$this->parsable = self::PARSABLE_UNKNOWN;
++		$this->xmlParsableBuffer = '';
+ 	}
+ 
+ 	/** Destroy the xml parser
+@@ -117,6 +132,13 @@
+ 		xml_parser_free( $this->xmlParser );
+ 	}
+ 
++	/**
++	 * Check if this instance supports using this class
++	 */
++	public static function isSupported() {
++		return function_exists( 'xml_parser_create_ns' ) && class_exists( 'XMLReader' );
++	}
++
+ 	/** Get the result array. Do some post-processing before returning
+ 	* the array, and transform any metadata that is special-cased.
+ 	*
+@@ -263,6 +285,27 @@
+ 				wfRestoreWarnings();
+ 			}
+ 
++			// Ensure the XMP block does not have an xml doctype declaration, which
++			// could declare entities unsafe to parse with xml_parse (T85848/T71210).
++			if ( $this->parsable !== self::PARSABLE_OK ) {
++				if ( $this->parsable === self::PARSABLE_NO ) {
++					throw new MWException( 'Unsafe doctype declaration in XML.' );
++				}
++
++				$content = $this->xmlParsableBuffer . $content;
++				if ( !$this->checkParseSafety( $content ) ) {
++					if ( !$allOfIt && $this->parsable !== self::PARSABLE_NO ) {
++						// parse wasn't Unsuccessful yet, so return true
++						// in this case.
++						return true;
++					}
++					$msg = ( $this->parsable === self::PARSABLE_NO ) ?
++						'Unsafe doctype declaration in XML.' :
++						'No root element found in XML.';
++					throw new MWException( $msg );
++				}
++			}
++
+ 			$ok = xml_parse( $this->xmlParser, $content, $allOfIt );
+ 			if ( !$ok ) {
+ 				$error = xml_error_string( xml_get_error_code( $this->xmlParser ) );
+@@ -385,6 +428,59 @@
+ 
+ 	}
+ 
++	/**
++	 * Check if a block of XML is safe to pass to xml_parse, i.e. doesn't
++	 * contain a doctype declaration which could contain a dos attack if we
++	 * parse it and expand internal entities (T85848).
++	 *
++	 * @param string $content xml string to check for parse safety
++	 * @return bool true if the xml is safe to parse, false otherwise
++	 */
++	private function checkParseSafety( $content ) {
++		$reader = new XMLReader();
++		$result = null;
++
++		// For XMLReader to parse incomplete/invalid XML, it has to be open()'ed
++		// instead of using XML().
++		$reader->open(
++			'data://text/plain,' . urlencode( $content ),
++			null,
++			LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NONET
++		);
++
++		$oldDisable = libxml_disable_entity_loader( true );
++		$reader->setParserProperty( XMLReader::SUBST_ENTITIES, false );
++
++		// Even with LIBXML_NOWARNING set, XMLReader::read gives a warning
++		// when parsing truncated XML, which causes unit tests to fail.
++		wfSuppressWarnings();
++		while ( $reader->read() ) {
++			if ( $reader->nodeType === XMLReader::ELEMENT ) {
++				// Reached the first element without hitting a doctype declaration
++				$this->parsable = self::PARSABLE_OK;
++				$result = true;
++				break;
++			}
++			if ( $reader->nodeType === XMLReader::DOC_TYPE ) {
++				$this->parsable = self::PARSABLE_NO;
++				$result = false;
++				break;
++			}
++		}
++		wfRestoreWarnings();
++		libxml_disable_entity_loader( $oldDisable );
++
++		if ( !is_null( $result ) ) {
++			return $result;
++		}
++
++		// Reached the end of the parsable xml without finding an element
++		// or doctype. Buffer and try again.
++		$this->parsable = self::PARSABLE_BUFFERING;
++		$this->xmlParsableBuffer = $content;
++		return false;
++	}
++
+ 	/** When we hit a closing element in MODE_IGNORE
+ 	* Check to see if this is the element we started to ignore,
+ 	* in which case we get out of MODE_IGNORE
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/OutputPage.php mediawiki-1.19.24/includes/OutputPage.php
+--- mediawiki-1.19.23/includes/OutputPage.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/OutputPage.php	2015-03-31 13:23:38.000000000 +0000
+@@ -2975,6 +2975,10 @@
+ 		if ( !$this->getTitle()->isJsSubpage() && !$this->getTitle()->isCssSubpage() ) {
+ 			return false;
+ 		}
++		if ( !$this->getTitle()->isSubpageOf( $this->getUser()->getUserPage() ) ) {
++			// Don't execute another user's CSS or JS on preview (T85855)
++			return false;
++		}
+ 
+ 		return !count( $this->getTitle()->getUserPermissionsErrors( 'edit', $this->getUser() ) );
+ 	}
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/upload/UploadBase.php mediawiki-1.19.24/includes/upload/UploadBase.php
+--- mediawiki-1.19.23/includes/upload/UploadBase.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/upload/UploadBase.php	2015-03-31 13:23:38.000000000 +0000
+@@ -1210,23 +1210,22 @@
+ 				}
+ 			}
+ 
+-			# href with embeded svg as target
+-			if( $stripped == 'href' && preg_match( '!data:[^,]*image/svg[^,]*,!sim', $value ) ) {
+-				wfDebug( __METHOD__ . ": Found href to embedded svg \"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
++			# only allow data: targets that should be safe. This prevents vectors like,
++			# image/svg, text/xml, application/xml, and text/html, which can contain scripts
++			if ( $stripped == 'href' && strncasecmp( 'data:', $value, 5 ) === 0 ) {
++				// rfc2397 parameters. This is only slightly slower than (;[\w;]+)*.
++				$parameters = '(?>;[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+=(?>[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+|"(?>[\0-\x0c\x0e-\x21\x23-\x5b\x5d-\x7f]+|\\\\[\0-\x7f])*"))*(?:;base64)?';
++				if ( !preg_match( "!^data:\s*image/(gif|jpeg|jpg|png)$parameters,!i", $value ) ) {
++					wfDebug( __METHOD__ . ": Found href to unwhitelisted data: uri "
++						. "\"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
+ 				return true;
+ 			}
+-
+-			# href with embeded (text/xml) svg as target
+-			if( $stripped == 'href' && preg_match( '!data:[^,]*text/xml[^,]*,!sim', $value ) ) {
+-				wfDebug( __METHOD__ . ": Found href to embedded svg \"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
+-				return true;
+ 			}
+ 
+-			# Change href with animate from (http://html5sec.org/#137). This doesn't seem
+-			# possible without embedding the svg, but filter here in case.
+-			if ( $stripped == 'from'
++			# Change href with animate from (http://html5sec.org/#137).
++			if ( $stripped === 'attributename'
+ 				&& $strippedElement === 'animate'
+-				&& !preg_match( '!^https?://!im', $value )
++				&& $this->stripXmlNamespace( $value ) == 'href'
+ 			) {
+ 				wfDebug( __METHOD__ . ": Found animate that might be changing href using from "
+ 					. "\"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
+@@ -1300,7 +1299,7 @@
+ 	private static function checkCssFragment( $value ) {
+ 
+ 		# Forbid external stylesheets, for both reliability and to protect viewer's privacy
+-		if ( strpos( $value, '@import' ) !== false ) {
++		if ( stripos( $value, '@import' ) !== false ) {
+ 			return true;
+ 		}
+ 
+diff -Nruw -x '*~' -x '.js*' -x '.git*' -x '*.xcf' -x '#*#' -x '.#*' -x '.rubocop*' -x .travis.yml -x package.json -x messages -x Gemfile -x '*.png' -x '*.jpg' -x '*.xcf' -x '*.gif' -x '*.svg' -x '*.tiff' -x '*.zip' -x '*.xmp' mediawiki-1.19.23/includes/XmlTypeCheck.php mediawiki-1.19.24/includes/XmlTypeCheck.php
+--- mediawiki-1.19.23/includes/XmlTypeCheck.php	2015-03-31 13:24:03.000000000 +0000
++++ mediawiki-1.19.24/includes/XmlTypeCheck.php	2015-03-31 13:23:38.000000000 +0000
+@@ -1,11 +1,36 @@
+ <?php
++/**
++ * XML syntax and type checker.
++ *
++ * Since 1.24.2, it uses XMLReader instead of xml_parse, which gives us
++ * more control over the expansion of XML entities. When passed to the
++ * callback, entities will be fully expanded, but may report the XML is
++ * invalid if expanding the entities are likely to cause a DoS.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License along
++ * with this program; if not, write to the Free Software Foundation, Inc.,
++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ * @file
++ */
+ 
+ class XmlTypeCheck {
+ 	/**
+ 	 * Will be set to true or false to indicate whether the file is
+ 	 * well-formed XML. Note that this doesn't check schema validity.
+ 	 */
+-	public $wellFormed = false;
++	public $wellFormed = null;
+ 
+ 	/**
+ 	 * Will be set to true if the optional element filter returned
+@@ -44,8 +69,8 @@
+ 	);
+ 
+ 	/**
+-	 * @param $file string filename
+-	 * @param $filterCallback callable (optional)
++	 * @param string $input a filename
++	 * @param callable $filterCallback (optional)
+ 	 *        Function to call to do additional custom validity checks from the
+ 	 *        SAX element handler event. This gives you access to the element
+ 	 *        namespace, name, attributes, and text contents.
+@@ -53,10 +78,10 @@
+ 	 * @param array $options list of additional parsing options:
+ 	 *	processing_instruction_handler: Callback for xml_set_processing_instruction_handler
+ 	 */
+-	function __construct( $file, $filterCallback=null, $options=array() ) {
++	function __construct( $input, $filterCallback = null, $options = array() ) {
+ 		$this->filterCallback = $filterCallback;
+ 		$this->parserOptions = array_merge( $this->parserOptions, $options );
+-		$this->run( $file );
++		$this->validateFromInput( $input, true );
+ 	}
+ 
+ 	/**
+@@ -68,119 +93,211 @@
+ 		return $this->rootElement;
+ 	}
+ 
++
+ 	/**
+-	 * @param $fname
++	 * @param string $fname the filename
+ 	 */
+-	private function run( $fname ) {
+-		$parser = xml_parser_create_ns( 'UTF-8' );
+-
+-		// case folding violates XML standard, turn it off
+-		xml_parser_set_option( $parser, XML_OPTION_CASE_FOLDING, false );
++	private function validateFromInput( $xml, $isFile ) {
++		$reader = new XMLReader();
++		if ( $isFile ) {
++			$s = $reader->open( $xml, null, LIBXML_NOERROR | LIBXML_NOWARNING );
++		} else {
++			$s = $reader->XML( $xml, null, LIBXML_NOERROR | LIBXML_NOWARNING );
++		}
++		if ( $s !== true ) {
++			// Couldn't open the XML
++			$this->wellFormed = false;
++		} else {
++			$oldDisable = libxml_disable_entity_loader( true );
++			$reader->setParserProperty( XMLReader::SUBST_ENTITIES, true );
++			try {
++				$this->validate( $reader );
++			} catch ( Exception $e ) {
++				// Calling this malformed, because we didn't parse the whole
++				// thing. Maybe just an external entity refernce.
++				$this->wellFormed = false;
++				$reader->close();
++				libxml_disable_entity_loader( $oldDisable );
++				throw $e;
++			}
++			$reader->close();
++			libxml_disable_entity_loader( $oldDisable );
++		}
++	}
+ 
+-		xml_set_element_handler( $parser, array( $this, 'rootElementOpen' ), false );
++	private function readNext( XMLReader $reader ) {
++		set_error_handler( array( $this, 'XmlErrorHandler' ) );
++		$ret = $reader->read();
++		restore_error_handler();
++		return $ret;
++	}
+ 
+-		if ( $this->parserOptions['processing_instruction_handler'] ) {
+-			xml_set_processing_instruction_handler(
+-				$parser,
+-				array( $this, 'processingInstructionHandler' )
+-			);
++	public function XmlErrorHandler( $errno, $errstr ) {
++		$this->wellFormed = false;
+ 		}
+ 
+-		if ( file_exists( $fname ) ) {
+-			$file = fopen( $fname, "rb" );
+-			if ( $file ) {
++	private function validate( $reader ) {
++
++		// First, move through anything that isn't an element, and
++		// handle any processing instructions with the callback
+ 				do {
+-					$chunk = fread( $file, 32768 );
+-					$ret = xml_parse( $parser, $chunk, feof( $file ) );
+-					if( $ret == 0 ) {
+-						// XML isn't well-formed!
+-						fclose( $file );
+-						xml_parser_free( $parser );
++			if( !$this->readNext( $reader ) ) {
++				// Hit the end of the document before any elements
++				$this->wellFormed = false;
+ 						return;
+ 					}
+-				} while( !feof( $file ) );
++			if ( $reader->nodeType === XMLReader::PI ) {
++				$this->processingInstructionHandler( $reader->name, $reader->value );
++			}
++		} while ( $reader->nodeType != XMLReader::ELEMENT );
+ 
+-				fclose( $file );
++		// Process the rest of the document
++		do {
++			switch ( $reader->nodeType ) {
++				case XMLReader::ELEMENT:
++					$name = $this->expandNS(
++						$reader->name,
++						$reader->namespaceURI
++					);
++					if ( $this->rootElement === '' ) {
++						$this->rootElement = $name;
+ 			}
++					$empty = $reader->isEmptyElement;
++					$attrs = $this->getAttributesArray( $reader );
++					$this->elementOpen( $name, $attrs );
++					if ( $empty ) {
++						$this->elementClose();
++					}
++					break;
++
++				case XMLReader::END_ELEMENT:
++					$this->elementClose();
++					break;
++
++				case XMLReader::WHITESPACE:
++				case XMLReader::SIGNIFICANT_WHITESPACE:
++				case XMLReader::CDATA:
++				case XMLReader::TEXT:
++					$this->elementData( $reader->value );
++					break;
++
++				case XMLReader::ENTITY_REF:
++					// Unexpanded entity (maybe external?),
++					// don't send to the filter (xml_parse didn't)
++					break;
++
++				case XMLReader::COMMENT:
++					// Don't send to the filter (xml_parse didn't)
++					break;
++
++				case XMLReader::PI:
++					// Processing instructions can happen after the header too
++					$this->processingInstructionHandler(
++						$reader->name,
++						$reader->value
++					);
++					break;
++				default:
++					// One of DOC, DOC_TYPE, ENTITY, END_ENTITY,
++					// NOTATION, or XML_DECLARATION
++					// xml_parse didn't send these to the filter, so we won't.
+ 		}
+ 
++		} while ( $this->readNext( $reader ) );
++
++		if ( $this->stackDepth !== 0 ) {
++			$this->wellFormed = false;
++		} elseif ( $this->wellFormed === null ) {
+ 		$this->wellFormed = true;
++		}
+ 
+-		xml_parser_free( $parser );
+ 	}
+ 
+ 	/**
+-	 * @param $parser
+-	 * @param $name
+-	 * @param $attribs
++	 * Get all of the attributes for an XMLReader's current node
++	 * @param $r XMLReader
++	 * @return array of attributes
+ 	 */
+-	private function rootElementOpen( $parser, $name, $attribs ) {
+-		$this->rootElement = $name;
++	private function getAttributesArray( XMLReader $r ) {
++		$attrs = array();
++		while ( $r->moveToNextAttribute() ) {
++			if ( $r->namespaceURI === 'http://www.w3.org/2000/xmlns/' ) {
++				// XMLReader treats xmlns attributes as normal
++				// attributes, while xml_parse doesn't
++				continue;
++			}
++			$name = $this->expandNS( $r->name, $r->namespaceURI );
++			$attrs[$name] = $r->value;
++		}
++		return $attrs;
++	}
+ 
+-		if( is_callable( $this->filterCallback ) ) {
+-			xml_set_element_handler(
+-				$parser,
+-				array( $this, 'elementOpen' ),
+-				array( $this, 'elementClose' )
+-			);
+-			xml_set_character_data_handler( $parser, array( $this, 'elementData' ) );
+-			$this->elementOpen( $parser, $name, $attribs );
+-		} else {
+-			// We only need the first open element
+-			xml_set_element_handler( $parser, false, false );
++	/**
++	 * @param $name element or attribute name, maybe with a full or short prefix
++	 * @param $namespaceURI the namespaceURI
++	 * @return string the name prefixed with namespaceURI
++	 */
++	private function expandNS( $name, $namespaceURI ) {
++		if ( $namespaceURI ) {
++			$parts = explode( ':', $name );
++			$localname = array_pop( $parts );
++			return "$namespaceURI:$localname";
+ 		}
++		return $name;
+ 	}
+ 
+ 	/**
+-	 * @param $parser
+ 	 * @param $name
+ 	 * @param $attribs
+ 	 */
+-	private function elementOpen( $parser, $name, $attribs ) {
++	private function elementOpen( $name, $attribs ) {
+ 		$this->elementDataContext[] = array( $name, $attribs );
+ 		$this->elementData[] = '';
+ 		$this->stackDepth++;
+ 	}
+ 
+ 	/**
+-	 * @param $parser
+-	 * @param $name
+ 	 */
+-	private function elementClose( $parser, $name ) {
++	private function elementClose() {
+ 		list( $name, $attribs ) = array_pop( $this->elementDataContext );
+ 		$data = array_pop( $this->elementData );
+ 		$this->stackDepth--;
+ 
+-		if ( call_user_func(
++		if ( is_callable( $this->filterCallback )
++			&& call_user_func(
+ 			$this->filterCallback,
+ 			$name,
+ 			$attribs,
+ 			$data
+-		) ) {
+-			// Filter hit!
++			)
++		) {
++			// Filter hit
+ 			$this->filterMatch = true;
+ 		}
+ 	}
+ 
+ 	/**
+-	 * @param $parser
+ 	 * @param $data
+ 	 */
+-	private function elementData( $parser, $data ) {
+-		// xml_set_character_data_handler breaks the data on & characters, so
+-		// we collect any data here, and we'll run the callback in elementClose
++	private function elementData( $data ) {
++		// Collect any data here, and we'll run the callback in elementClose
+ 		$this->elementData[ $this->stackDepth - 1 ] .= trim( $data );
+ 	}
+ 
+ 	/**
+-	 * @param $parser
+ 	 * @param $target
+ 	 * @param $data
+ 	 */
+-	private function processingInstructionHandler( $parser, $target, $data ) {
+-		if ( call_user_func( $this->parserOptions['processing_instruction_handler'], $target, $data ) ) {
++	private function processingInstructionHandler( $target, $data ) {
++		if ( $this->parserOptions['processing_instruction_handler'] ) {
++			if ( call_user_func(
++				$this->parserOptions['processing_instruction_handler'],
++				$target,
++				$data
++			) ) {
+ 			// Filter hit!
+ 			$this->filterMatch = true;
+ 		}
+ 	}
+ }
++}
diff -Nru mediawiki-1.19.20+dfsg/debian/patches/series mediawiki-1.19.20+dfsg/debian/patches/series
--- mediawiki-1.19.20+dfsg/debian/patches/series	2014-12-21 12:10:23.000000000 +0000
+++ mediawiki-1.19.20+dfsg/debian/patches/series	2015-04-06 17:02:16.000000000 +0000
@@ -12,3 +12,4 @@
 CVE-2014-9277_1.patch
 CVE-2014-9277_2.patch
 T76686.patch
+security_1.19.24.patch

--- End Message ---
--- Begin Message ---
On 2015-04-08 15:10, Thijs Kinkhorst wrote:
> Package: release.debian.org
> Severity: normal
> User: release.debian.org@packages.debian.org
> Usertags: unblock
> 
> Please unblock package mediawiki.
> 
> The only change is an addition of an upstream patch for this release branch
> which fixes a number of security issues.
> 
> unblock mediawiki/1:1.19.20+dfsg-2.3
> 
> Thanks,
> Thijs
> 

Unblocked, thanks.

~Niels

--- End Message ---

Reply to: