[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