[lucene-solr] 01/02: Fixes for security vulnerabilities:
James Downing Page
jamespage at moszumanska.debian.org
Sat Dec 14 22:09:35 UTC 2013
This is an automated email from the git hooks/post-receive script.
jamespage pushed a commit to branch master
in repository lucene-solr.
commit 26a4b9e0b455e46e7ff22e0aa15c1dddc76ab89d
Author: James Page <james.page at ubuntu.com>
Date: Fri Dec 6 12:29:41 2013 +0000
Fixes for security vulnerabilities:
* Fixes for new security vulnerabilities (Closes: #731113):
- debian/patches/CVE-2013-6397.patch:
Fix DocumentAnalysisRequestHandler to correctly use
EmptyEntityResolver to prevent loading of external entities like
UpdateRequestHandler does.
CVE-2013-6397
- debian/patches/CVE-2013-6407_CVE-2013-6408.patch:
XML and XSLT UpdateRequestHandler should not try to
resolve external entities. This improves speed of loading e.g.
XSL-transformed XHTML documents.
CVE-2013-6407
Fix XML parsing in XPathEntityProcessor to correctly
expand named entities, but ignore external entities.
CVE-2013-6408
---
debian/changelog | 19 +
debian/patches/CVE-2013-6397.patch | 177 +++++++++
debian/patches/CVE-2013-6407_CVE-2013-6408.patch | 480 +++++++++++++++++++++++
debian/patches/series | 2 +
4 files changed, 678 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 9ce056a..50ec9f9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,22 @@
+lucene-solr (3.6.2+dfsg-2) unstable; urgency=low
+
+ * Fixes for new security vulnerabilities (Closes: #731113):
+ - debian/patches/CVE-2013-6397.patch:
+ Fix DocumentAnalysisRequestHandler to correctly use
+ EmptyEntityResolver to prevent loading of external entities like
+ UpdateRequestHandler does.
+ CVE-2013-6397
+ - debian/patches/CVE-2013-6407_CVE-2013-6408.patch:
+ XML and XSLT UpdateRequestHandler should not try to
+ resolve external entities. This improves speed of loading e.g.
+ XSL-transformed XHTML documents.
+ CVE-2013-6407
+ Fix XML parsing in XPathEntityProcessor to correctly
+ expand named entities, but ignore external entities.
+ CVE-2013-6408
+
+ -- James Page <james.page at ubuntu.com> Sat, 14 Dec 2013 22:07:54 +0000
+
lucene-solr (3.6.2+dfsg-1) unstable; urgency=low
* Upload to unstable.
diff --git a/debian/patches/CVE-2013-6397.patch b/debian/patches/CVE-2013-6397.patch
new file mode 100644
index 0000000..d26a1b1
--- /dev/null
+++ b/debian/patches/CVE-2013-6397.patch
@@ -0,0 +1,177 @@
+Description: Fix for CVE-2013-6397
+Origin: https://issues.apache.org/jira/browse/SOLR-4882
+
+--- a/solr/contrib/velocity/src/java/org/apache/solr/response/VelocityResponseWriter.java
++++ b/solr/contrib/velocity/src/java/org/apache/solr/response/VelocityResponseWriter.java
+@@ -64,7 +64,6 @@ public class VelocityResponseWriter impl
+ } catch (ClassCastException e) {
+ // known edge case where QueryResponse's extraction assumes "response" is a SolrDocumentList
+ // (AnalysisRequestHandler emits a "response")
+- e.printStackTrace();
+ rsp = new SolrResponseBase();
+ rsp.setResponse(parsedResponse);
+ }
+@@ -123,6 +122,7 @@ public class VelocityResponseWriter impl
+ SolrVelocityResourceLoader resourceLoader =
+ new SolrVelocityResourceLoader(request.getCore().getSolrConfig().getResourceLoader());
+ engine.setProperty("solr.resource.loader.instance", resourceLoader);
++ engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "params,solr");
+
+ // TODO: Externalize Velocity properties
+ engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "params,file,solr");
+--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
++++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+@@ -25,6 +25,7 @@ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.InputStreamReader;
+ import java.net.MalformedURLException;
++import java.net.URI;
+ import java.net.URL;
+ import java.net.URLClassLoader;
+ import java.util.*;
+@@ -212,7 +213,7 @@ public class SolrResourceLoader implemen
+ }
+
+ public String getConfigDir() {
+- return instanceDir + "conf/";
++ return instanceDir + "conf" + File.separator;
+ }
+
+ public String getDataDir() {
+@@ -250,27 +251,46 @@ public class SolrResourceLoader implemen
+ public InputStream openResource(String resource) {
+ InputStream is=null;
+ try {
+- File f0 = new File(resource);
+- File f = f0;
++ File f0 = new File(resource), f = f0;
+ if (!f.isAbsolute()) {
+ // try $CWD/$configDir/$resource
+- f = new File(getConfigDir() + resource);
++ f = new File(getConfigDir() + resource).getAbsoluteFile();
+ }
+- if (f.isFile() && f.canRead()) {
++ boolean found = f.isFile() && f.canRead();
++ if (!found) { // no success with $CWD/$configDir/$resource
++ f = f0.getAbsoluteFile();
++ found = f.isFile() && f.canRead();
++ }
++ // check that we don't escape instance dir
++ if (found) {
++ if (!Boolean.parseBoolean(System.getProperty("solr.allow.unsafe.resourceloading", "false"))) {
++ final URI instanceURI = new File(getInstanceDir()).getAbsoluteFile().toURI().normalize();
++ final URI fileURI = f.toURI().normalize();
++ if (instanceURI.relativize(fileURI) == fileURI) {
++ // no URI relativize possible, so they don't share same base folder
++ throw new RuntimeException("For security reasons, SolrResourceLoader cannot load files from outside the instance's directory: " + f +
++ "; if you want to override this safety feature and you are sure about the consequences, you can pass the system property "+
++ "-Dsolr.allow.unsafe.resourceloading=true to your JVM");
++ }
++ }
++ // relativize() returned a relative, new URI, so we are fine!
+ return new FileInputStream(f);
+- } else if (f != f0) { // no success with $CWD/$configDir/$resource
+- if (f0.isFile() && f0.canRead())
+- return new FileInputStream(f0);
+ }
+- // delegate to the class loader (looking into $INSTANCE_DIR/lib jars)
+- is = classLoader.getResourceAsStream(resource);
+- if (is == null)
+- is = classLoader.getResourceAsStream(getConfigDir() + resource);
++ // Delegate to the class loader (looking into $INSTANCE_DIR/lib jars).
++ // We need a ClassLoader-compatible (forward-slashes) path here!
++ is = classLoader.getResourceAsStream(resource.replace(File.separatorChar, '/'));
++ // This is a hack just for tests (it is not done in ZKResourceLoader)!
++ // -> the getConfigDir's path must not be absolute!
++ if (is == null && System.getProperty("jetty.testMode") != null && !new File(getConfigDir()).isAbsolute()) {
++ is = classLoader.getResourceAsStream((getConfigDir() + resource).replace(File.separatorChar, '/'));
++ }
++ } catch (RuntimeException re) {
++ throw re; // preserve original Exception
+ } catch (Exception e) {
+ throw new RuntimeException("Error opening " + resource, e);
+ }
+ if (is==null) {
+- throw new RuntimeException("Can't find resource '" + resource + "' in classpath or '" + getConfigDir() + "', cwd="+System.getProperty("user.dir"));
++ throw new RuntimeException("Can't find resource '" + resource + "' in classpath or '" + new File(getConfigDir()).getAbsolutePath() + "'");
+ }
+ return is;
+ }
+--- a/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java
++++ b/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java
+@@ -19,9 +19,10 @@ package org.apache.solr.core;
+
+ import junit.framework.Assert;
+
+-import org.apache.lucene.util.LuceneTestCase;
++import org.apache.lucene.util._TestUtil;
+ import org.apache.solr.analysis.KeywordTokenizerFactory;
+ import org.apache.solr.analysis.NGramFilterFactory;
++import org.apache.solr.SolrTestCaseJ4;
+ import org.apache.solr.common.SolrException;
+ import org.apache.solr.handler.admin.LukeRequestHandler;
+ import org.apache.solr.handler.component.FacetComponent;
+@@ -30,12 +31,13 @@ import org.apache.solr.util.plugin.Resou
+ import org.apache.solr.util.plugin.SolrCoreAware;
+
+ import java.io.File;
++import java.io.IOException;
+ import java.io.InputStream;
+ import java.nio.charset.CharacterCodingException;
+ import java.util.Arrays;
+ import java.util.List;
+
+-public class ResourceLoaderTest extends LuceneTestCase
++public class ResourceLoaderTest extends SolrTestCaseJ4
+ {
+ public void testInstanceDir() throws Exception {
+ SolrResourceLoader loader = new SolrResourceLoader(null);
+@@ -47,7 +49,27 @@ public class ResourceLoaderTest extends
+ assertTrue(instDir + " is not equal to " + "solr/", instDir.equals("solr" + File.separator) == true);
+ }
+
+- public void testAwareCompatibility()
++ public void testEscapeInstanceDir() throws Exception {
++ File temp = _TestUtil.getTempDir("testEscapeInstanceDir");
++ try {
++ temp.mkdirs();
++ new File(temp, "dummy.txt").createNewFile();
++ File instanceDir = new File(temp, "instance");
++ instanceDir.mkdir();
++ new File(instanceDir, "conf").mkdir();
++ SolrResourceLoader loader = new SolrResourceLoader(instanceDir.getAbsolutePath());
++ try {
++ loader.openResource("../../dummy.txt").close();
++ fail();
++ } catch (RuntimeException re) {
++ assertTrue(re.getMessage().startsWith("For security reasons, SolrResourceLoader"));
++ }
++ } finally {
++ _TestUtil.rmDir(temp);
++ }
++ }
++
++ public void testAwareCompatibility() throws Exception
+ {
+ SolrResourceLoader loader = new SolrResourceLoader( "." );
+
+--- a/solr/core/src/test/org/apache/solr/schema/PrimitiveFieldTypeTest.java
++++ b/solr/core/src/test/org/apache/solr/schema/PrimitiveFieldTypeTest.java
+@@ -41,10 +41,17 @@ public class PrimitiveFieldTypeTest exte
+ // set some system properties for use by tests
+ System.setProperty("solr.test.sys.prop1", "propone");
+ System.setProperty("solr.test.sys.prop2", "proptwo");
++ System.setProperty("solr.allow.unsafe.resourceloading", "true");
+
+ initMap = new HashMap<String,String>();
+ config = new SolrConfig(testConfHome + "solrconfig.xml");
+ }
++
++ @Override
++ public void tearDown() throws Exception {
++ System.clearProperty("solr.allow.unsafe.resourceloading");
++ super.tearDown();
++ }
+
+ @SuppressWarnings("deprecation")
+ @Test
diff --git a/debian/patches/CVE-2013-6407_CVE-2013-6408.patch b/debian/patches/CVE-2013-6407_CVE-2013-6408.patch
new file mode 100644
index 0000000..2eacbad
--- /dev/null
+++ b/debian/patches/CVE-2013-6407_CVE-2013-6408.patch
@@ -0,0 +1,480 @@
+Description: Fixes for CVE-2013-6407 and CVE-2013-6408
+Origin: https://issues.apache.org/jira/browse/SOLR-5520
+
+--- a/solr/CHANGES.txt
++++ b/solr/CHANGES.txt
+@@ -20,6 +20,17 @@ when more advanced customization is requ
+ See README.txt and http://lucene.apache.org/solr for more information
+ on how to get started.
+
++* SOLR-5520, SOLR-4881: Fix DocumentAnalysisRequestHandler to correctly use
++ EmptyEntityResolver to prevent loading of external entities like
++ UpdateRequestHandler does. (Hossman, Uwe Schindler)
++
++* SOLR-5520, SOLR-3895: XML and XSLT UpdateRequestHandler should not try to
++ resolve external entities. This improves speed of loading e.g.
++ XSL-transformed XHTML documents. (Martin Herfurt, uschindler, hossman)
++
++* SOLR-5520, SOLR-3614: Fix XML parsing in XPathEntityProcessor to correctly
++ expand named entities, but ignore external entities. (uschindler, hossman)
++
+ ================== 3.6.2 ==================
+
+ Bug Fixes
+--- a/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/XPathRecordReader.java
++++ b/solr/contrib/dataimporthandler/src/java/org/apache/solr/handler/dataimport/XPathRecordReader.java
+@@ -17,6 +17,7 @@
+ package org.apache.solr.handler.dataimport;
+
+ import org.apache.solr.common.util.XMLErrorLogger;
++import org.apache.solr.util.EmptyEntityResolver;
+ import javax.xml.stream.XMLInputFactory;
+ import static javax.xml.stream.XMLStreamConstants.*;
+ import javax.xml.stream.XMLStreamException;
+@@ -625,10 +626,22 @@ public class XPathRecordReader {
+ }
+
+ static XMLInputFactory factory = XMLInputFactory.newInstance();
+- static{
+- factory.setProperty(XMLInputFactory.IS_VALIDATING , Boolean.FALSE);
+- factory.setProperty(XMLInputFactory.SUPPORT_DTD , Boolean.FALSE);
++ static {
++ EmptyEntityResolver.configureXMLInputFactory(factory);
+ factory.setXMLReporter(XMLLOG);
++ try {
++ // The java 1.6 bundled stax parser (sjsxp) does not currently have a thread-safe
++ // XMLInputFactory, as that implementation tries to cache and reuse the
++ // XMLStreamReader. Setting the parser-specific "reuse-instance" property to false
++ // prevents this.
++ // All other known open-source stax parsers (and the bea ref impl)
++ // have thread-safe factories.
++ factory.setProperty("reuse-instance", Boolean.FALSE);
++ } catch (IllegalArgumentException ex) {
++ // Other implementations will likely throw this exception since "reuse-instance"
++ // isimplementation specific.
++ LOG.debug("Unable to set the 'reuse-instance' property for the input chain: " + factory);
++ }
+ }
+
+ /**Implement this interface to stream records as and when one is found.
+--- a/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestXPathEntityProcessor.java
++++ b/solr/contrib/dataimporthandler/src/test/org/apache/solr/handler/dataimport/TestXPathEntityProcessor.java
+@@ -87,7 +87,11 @@ public class TestXPathEntityProcessor ex
+ break;
+ result.add(row);
+ }
+- assertEquals(2, ((List)result.get(0).get("a")).size());
++ List l = (List)result.get(0).get("a");
++ assertEquals(3, l.size());
++ assertEquals("1", l.get(0));
++ assertEquals("2", l.get(1));
++ assertEquals("ü", l.get(2));
+ }
+
+ @Test
+@@ -298,7 +302,7 @@ public class TestXPathEntityProcessor ex
+ + "\t\t<price>9.90</price>\n"
+ + "\t\t<year>1982</year>\n" + "\t</cd>\n" + "</catalog>\t";
+
+- private static final String testXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><a>1</a><a>2</a></root>";
++ private static final String testXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE root [\n<!ENTITY uuml \"ü\" >\n]>\n<root><a>1</a><a>2</a><a>ü</a></root>";
+
+ private static final String testXmlFlatten = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><a>1<b>B</b>2</a></root>";
+ }
+--- a/solr/core/src/java/org/apache/solr/handler/DocumentAnalysisRequestHandler.java
++++ b/solr/core/src/java/org/apache/solr/handler/DocumentAnalysisRequestHandler.java
+@@ -36,6 +36,7 @@ import org.apache.solr.request.SolrQuery
+ import org.apache.solr.schema.FieldType;
+ import org.apache.solr.schema.IndexSchema;
+ import org.apache.solr.schema.SchemaField;
++import org.apache.solr.util.EmptyEntityResolver;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+@@ -91,6 +92,8 @@ public class DocumentAnalysisRequestHand
+ super.init(args);
+
+ inputFactory = XMLInputFactory.newInstance();
++ EmptyEntityResolver.configureXMLInputFactory(inputFactory);
++ inputFactory.setXMLReporter(xmllog);
+ try {
+ // The java 1.6 bundled stax parser (sjsxp) does not currently have a thread-safe
+ // XMLInputFactory, as that implementation tries to cache and reuse the
+@@ -104,7 +107,6 @@ public class DocumentAnalysisRequestHand
+ // isimplementation specific.
+ log.debug("Unable to set the 'reuse-instance' property for the input factory: " + inputFactory);
+ }
+- inputFactory.setXMLReporter(xmllog);
+ }
+
+ /**
+--- a/solr/core/src/java/org/apache/solr/handler/XmlUpdateRequestHandler.java
++++ b/solr/core/src/java/org/apache/solr/handler/XmlUpdateRequestHandler.java
+@@ -28,6 +28,7 @@ import org.apache.solr.request.SolrQuery
+ import org.apache.solr.response.SolrQueryResponse;
+ import org.apache.solr.update.processor.UpdateRequestProcessor;
+ import org.apache.solr.update.processor.UpdateRequestProcessorChain;
++import org.apache.solr.util.EmptyEntityResolver;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+@@ -89,6 +90,8 @@ public class XmlUpdateRequestHandler ext
+ super.init(args);
+
+ inputFactory = XMLInputFactory.newInstance();
++ inputFactory.setXMLReporter(xmllog);
++ EmptyEntityResolver.configureXMLInputFactory(inputFactory);
+ try {
+ // The java 1.6 bundled stax parser (sjsxp) does not currently have a thread-safe
+ // XMLInputFactory, as that implementation tries to cache and reuse the
+@@ -103,7 +106,6 @@ public class XmlUpdateRequestHandler ext
+ // isimplementation specific.
+ log.debug("Unable to set the 'reuse-instance' property for the input chain: " + inputFactory);
+ }
+- inputFactory.setXMLReporter(xmllog);
+ }
+
+ @Override
+--- a/solr/core/src/java/org/apache/solr/handler/XsltUpdateRequestHandler.java
++++ b/solr/core/src/java/org/apache/solr/handler/XsltUpdateRequestHandler.java
+@@ -22,10 +22,12 @@ import org.apache.solr.common.util.Named
+ import org.apache.solr.common.util.XMLErrorLogger;
+ import org.apache.solr.request.SolrQueryRequest;
+ import org.apache.solr.update.processor.UpdateRequestProcessor;
++import org.apache.solr.util.EmptyEntityResolver;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+
+ import javax.xml.stream.XMLInputFactory;
++import javax.xml.parsers.SAXParserFactory;
+
+ /**
+ * Add documents to solr using the STAX XML parser, transforming it with XSLT first
+@@ -41,6 +43,7 @@ public class XsltUpdateRequestHandler ex
+ private static final String XSLT_CACHE_PARAM = "xsltCacheLifetimeSeconds";
+
+ XMLInputFactory inputFactory;
++ SAXParserFactory saxFactory;
+ private Integer xsltCacheLifetimeSeconds;
+
+ @Override
+@@ -48,6 +51,8 @@ public class XsltUpdateRequestHandler ex
+ super.init(args);
+
+ inputFactory = XMLInputFactory.newInstance();
++ inputFactory.setXMLReporter(xmllog);
++ EmptyEntityResolver.configureXMLInputFactory(inputFactory);
+ try {
+ // The java 1.6 bundled stax parser (sjsxp) does not currently have a thread-safe
+ // XMLInputFactory, as that implementation tries to cache and reuse the
+@@ -62,7 +67,11 @@ public class XsltUpdateRequestHandler ex
+ // isimplementation specific.
+ log.debug("Unable to set the 'reuse-instance' property for the input chain: " + inputFactory);
+ }
+- inputFactory.setXMLReporter(xmllog);
++
++ // Init SAX parser (for XSL):
++ saxFactory = SAXParserFactory.newInstance();
++ saxFactory.setNamespaceAware(true); // XSL needs this!
++ EmptyEntityResolver.configureSAXParserFactory(saxFactory);
+
+ final SolrParams p = SolrParams.toSolrParams(args);
+ this.xsltCacheLifetimeSeconds = p.getInt(XSLT_CACHE_PARAM,XSLT_CACHE_DEFAULT);
+@@ -71,7 +80,7 @@ public class XsltUpdateRequestHandler ex
+
+ @Override
+ protected ContentStreamLoader newLoader(SolrQueryRequest req, UpdateRequestProcessor processor) {
+- return new XsltXMLLoader(processor, inputFactory, xsltCacheLifetimeSeconds);
++ return new XsltXMLLoader(processor, inputFactory, saxFactory, xsltCacheLifetimeSeconds);
+ }
+
+ //////////////////////// SolrInfoMBeans methods //////////////////////
+--- a/solr/core/src/java/org/apache/solr/handler/XsltXMLLoader.java
++++ b/solr/core/src/java/org/apache/solr/handler/XsltXMLLoader.java
+@@ -25,10 +25,12 @@ import org.apache.solr.common.util.Conte
+ import org.apache.solr.common.util.ContentStreamBase;
+ import org.apache.solr.common.util.XMLErrorLogger;
+ import org.apache.solr.core.SolrConfig;
++import org.apache.solr.util.EmptyEntityResolver;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ import org.apache.commons.io.IOUtils;
+
++import javax.xml.parsers.SAXParserFactory;
+ import javax.xml.stream.XMLStreamReader;
+ import javax.xml.stream.XMLStreamException;
+ import javax.xml.stream.XMLInputFactory;
+@@ -38,6 +40,7 @@ import javax.xml.transform.dom.DOMSource
+ import javax.xml.transform.dom.DOMResult;
+ import javax.xml.transform.sax.SAXSource;
+ import org.xml.sax.InputSource;
++import org.xml.sax.XMLReader;
+
+ import java.io.InputStream;
+ import java.io.IOException;
+@@ -50,14 +53,18 @@ import java.util.Map;
+ *
+ **/
+ class XsltXMLLoader extends XMLLoader {
++ public static Logger log = LoggerFactory.getLogger(XsltXMLLoader.class);
++ private static final XMLErrorLogger xmllog = new XMLErrorLogger(log);
+
+ public static final String TRANSFORM_PARAM = "tr";
+ public static final String CONTEXT_TRANSFORMER_KEY = "xsltupdater.transformer";
+
++ private final SAXParserFactory saxFactory;
+ private final Integer xsltCacheLifetimeSeconds;
+
+- public XsltXMLLoader(UpdateRequestProcessor processor, XMLInputFactory inputFactory, Integer xsltCacheLifetimeSeconds) {
++ public XsltXMLLoader(UpdateRequestProcessor processor, XMLInputFactory inputFactory, SAXParserFactory saxFactory, Integer xsltCacheLifetimeSeconds) {
+ super(processor, inputFactory);
++ this.saxFactory = saxFactory;
+ this.xsltCacheLifetimeSeconds = xsltCacheLifetimeSeconds;
+ }
+
+@@ -74,7 +81,10 @@ class XsltXMLLoader extends XMLLoader {
+ final String charset = ContentStreamBase.getCharsetFromContentType(stream.getContentType());
+ final InputSource isrc = new InputSource(is);
+ isrc.setEncoding(charset);
+- final SAXSource source = new SAXSource(isrc);
++ final XMLReader xmlr = saxFactory.newSAXParser().getXMLReader();
++ xmlr.setErrorHandler(xmllog);
++ xmlr.setEntityResolver(EmptyEntityResolver.SAX_INSTANCE);
++ final SAXSource source = new SAXSource(xmlr, isrc);
+ t.transform(source, result);
+ } catch(TransformerException te) {
+ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, te.getMessage(), te);
+--- /dev/null
++++ b/solr/core/src/java/org/apache/solr/util/EmptyEntityResolver.java
+@@ -0,0 +1,99 @@
++package org.apache.solr.util;
++
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one or more
++ * contributor license agreements. See the NOTICE file distributed with
++ * this work for additional information regarding copyright ownership.
++ * The ASF licenses this file to You under the Apache License, Version 2.0
++ * (the "License"); you may not use this file except in compliance with
++ * the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing, software
++ * distributed under the License is distributed on an "AS IS" BASIS,
++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ * See the License for the specific language governing permissions and
++ * limitations under the License.
++ */
++
++import java.io.InputStream;
++import org.xml.sax.InputSource;
++import org.xml.sax.EntityResolver;
++import javax.xml.XMLConstants;
++import javax.xml.parsers.SAXParserFactory;
++import javax.xml.stream.XMLInputFactory;
++import javax.xml.stream.XMLResolver;
++import javax.xml.transform.Source;
++import javax.xml.transform.stream.StreamSource;
++
++import org.apache.commons.io.input.ClosedInputStream;
++
++/**
++ * This class provides several singletons of entity resolvers used by
++ * SAX and StAX in the Java API. This is needed to make secure
++ * XML parsers, that don't resolve external entities from untrusted sources.
++ * <p>This class also provides static methods to configure SAX and StAX
++ * parsers to be safe.
++ * <p>Parsers will get an empty, closed stream for every external
++ * entity, so they will not fail while parsing (unless the external entity
++ * is needed for processing!).
++ */
++public final class EmptyEntityResolver {
++
++ public static final EntityResolver SAX_INSTANCE = new EntityResolver() {
++ // not in Java 5: @Override
++ public InputSource resolveEntity(String publicId, String systemId) {
++ return new InputSource(ClosedInputStream.CLOSED_INPUT_STREAM);
++ }
++ };
++
++ public static final XMLResolver STAX_INSTANCE = new XMLResolver() {
++ // not in Java 5: @Override
++ public InputStream resolveEntity(String publicId, String systemId, String baseURI, String namespace) {
++ return ClosedInputStream.CLOSED_INPUT_STREAM;
++ }
++ };
++
++ // no instance!
++ private EmptyEntityResolver() {}
++
++ private static void trySetSAXFeature(SAXParserFactory saxFactory, String feature, boolean enabled) {
++ try {
++ saxFactory.setFeature(feature, enabled);
++ } catch (Exception ex) {
++ // ignore
++ }
++ }
++
++ /** Configures the given {@link SAXParserFactory} to do secure XML processing of untrusted sources.
++ * It is required to also set {@link #SAX_INSTANCE} on the created {@link XMLReader}.
++ * @see #SAX_INSTANCE
++ */
++ public static void configureSAXParserFactory(SAXParserFactory saxFactory) {
++ // don't enable validation of DTDs:
++ saxFactory.setValidating(false);
++ // enable secure processing:
++ trySetSAXFeature(saxFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
++ }
++
++ private static void trySetStAXProperty(XMLInputFactory inputFactory, String key, Object value) {
++ try {
++ inputFactory.setProperty(key, value);
++ } catch (Exception ex) {
++ // ignore
++ }
++ }
++
++ /** Configures the given {@link XMLInputFactory} to not parse external entities.
++ * No further configuration on is needed, all required entity resolvers are configured.
++ */
++ public static void configureXMLInputFactory(XMLInputFactory inputFactory) {
++ // don't enable validation of DTDs:
++ trySetStAXProperty(inputFactory, XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
++ // enable this to *not* produce parsing failure on external entities:
++ trySetStAXProperty(inputFactory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.TRUE);
++ inputFactory.setXMLResolver(EmptyEntityResolver.STAX_INSTANCE);
++ }
++
++}
+--- a/solr/core/src/test/org/apache/solr/handler/XmlUpdateRequestHandlerTest.java
++++ b/solr/core/src/test/org/apache/solr/handler/XmlUpdateRequestHandlerTest.java
+@@ -17,6 +17,7 @@
+ package org.apache.solr.handler;
+
+ import org.apache.commons.lang.ObjectUtils;
++import org.apache.solr.common.util.NamedList;
+ import org.apache.solr.request.SolrQueryRequest;
+ import org.apache.solr.response.SolrQueryResponse;
+ import org.apache.solr.update.AddUpdateCommand;
+@@ -40,7 +41,7 @@ import org.junit.Test;
+
+ public class XmlUpdateRequestHandlerTest extends AbstractSolrTestCase
+ {
+- private XMLInputFactory inputFactory = XMLInputFactory.newInstance();
++ private XMLInputFactory inputFactory;
+ protected XmlUpdateRequestHandler handler;
+
+ @Override public String getSchemaFile() { return "schema.xml"; }
+@@ -50,6 +51,8 @@ public class XmlUpdateRequestHandlerTest
+ public void setUp() throws Exception {
+ super.setUp();
+ handler = new XmlUpdateRequestHandler();
++ handler.init(new NamedList<String>());
++ this.inputFactory = handler.inputFactory;
+ }
+
+ @Override
+@@ -118,6 +121,46 @@ public class XmlUpdateRequestHandlerTest
+ }
+
+ @Test
++ public void testExternalEntities() throws Exception
++ {
++ String file = getFile("mailing_lists.pdf").toURI().toASCIIString();
++ String xml =
++ "<?xml version=\"1.0\"?>" +
++ // check that external entities are not resolved!
++ "<!DOCTYPE foo [<!ENTITY bar SYSTEM \""+file+"\">]>" +
++ "<add>" +
++ " &bar;" +
++ " <doc>" +
++ " <field name=\"id\">12345</field>" +
++ " <field name=\"name\">kitten</field>" +
++ " </doc>" +
++ "</add>";
++ SolrQueryRequest req = req();
++ SolrQueryResponse rsp = new SolrQueryResponse();
++ BufferingRequestProcessor p = new BufferingRequestProcessor(null);
++ XMLLoader loader = new XMLLoader(p, inputFactory);
++ loader.load(req, rsp, new ContentStreamBase.StringStream(xml));
++
++ AddUpdateCommand add = p.addCommands.get(0);
++ assertEquals("12345", add.solrDoc.getField("id").getFirstValue());
++ req.close();
++ }
++
++ public void testNamedEntity() throws Exception {
++ assertU("<?xml version=\"1.0\" ?>\n"+
++ "<!DOCTYPE add [\n<!ENTITY wacky \"zzz\" >\n]>"+
++ "<add><doc>"+
++ "<field name=\"id\">1</field>"+
++ "<field name=\"foo_s\">&wacky;</field>" +
++ "</doc></add>");
++
++ assertU("<commit/>");
++ assertQ(req("foo_s:zzz"),
++ "//*[@numFound='1']"
++ );
++ }
++
++ @Test
+ public void testReadDelete() throws Exception {
+ String xml =
+ "<update>" +
+--- a/solr/core/src/test/org/apache/solr/handler/XsltUpdateRequestHandlerTest.java
++++ b/solr/core/src/test/org/apache/solr/handler/XsltUpdateRequestHandlerTest.java
+@@ -90,4 +90,54 @@ public class XsltUpdateRequestHandlerTes
+ , "//int[@name='id'][.='12345']"
+ );
+ }
++
++ @Test
++ public void testEntities() throws Exception
++ {
++ // use a binary file, so when it's loaded fail with XML eror:
++ String file = getFile("mailing_lists.pdf").toURI().toASCIIString();
++ String xml =
++ "<?xml version=\"1.0\"?>" +
++ "<!DOCTYPE foo [" +
++ // check that external entities are not resolved!
++ "<!ENTITY bar SYSTEM \""+file+"\">"+
++ // but named entities should be
++ "<!ENTITY wacky \"zzz\">"+
++ "]>" +
++ "<random>" +
++ " &bar;" +
++ " <document>" +
++ " <node name=\"id\" value=\"12345\"/>" +
++ " <node name=\"foo_s\" value=\"&wacky;\"/>" +
++ " </document>" +
++ "</random>";
++ Map<String,String> args = new HashMap<String, String>();
++ args.put("tr", "xsl-update-handler-test.xsl");
++
++ SolrCore core = h.getCore();
++ LocalSolrQueryRequest req = new LocalSolrQueryRequest( core, new MapSolrParams( args) );
++ ArrayList<ContentStream> streams = new ArrayList<ContentStream>();
++ streams.add(new ContentStreamBase.StringStream(xml));
++ req.setContentStreams(streams);
++ SolrQueryResponse rsp = new SolrQueryResponse();
++ XsltUpdateRequestHandler handler = new XsltUpdateRequestHandler();
++ handler.init(new NamedList<String>());
++ handler.handleRequestBody(req, rsp);
++ StringWriter sw = new StringWriter(32000);
++ QueryResponseWriter responseWriter = core.getQueryResponseWriter(req);
++ responseWriter.write(sw,req,rsp);
++ req.close();
++ String response = sw.toString();
++ assertU(response);
++ assertU(commit());
++
++ assertQ("test document was correctly committed", req("q","*:*")
++ , "//result[@numFound='1']"
++ , "//int[@name='id'][.='12345']"
++ );
++ assertQ("test document can be searched by the string defined by the named entity", req("q","foo_s:zzz")
++ , "//result[@numFound='1']"
++ , "//int[@name='id'][.='12345']"
++ );
++ }
+ }
diff --git a/debian/patches/series b/debian/patches/series
index be79de5..0a6edb8 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -6,3 +6,5 @@ icu4.4-compat.patch
regex-test-failure.patch
#set-data-dir.patch
remove-prettify.patch
+CVE-2013-6397.patch
+CVE-2013-6407_CVE-2013-6408.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/lucene-solr.git
More information about the pkg-java-commits
mailing list