Please find attached a patch which backports the security fix to the version of Spring present in Debian Wheezy.
diff --git a/debian/patches/CVE-2014-0225.patch b/debian/patches/CVE-2014-0225.patch new file mode 100644 index 0000000..9fe2e7b --- /dev/null +++ b/debian/patches/CVE-2014-0225.patch @@ -0,0 +1,305 @@ +--- a/projects/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java ++++ b/projects/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java +@@ -21,6 +21,7 @@ + import java.io.IOException; + import java.io.InputStream; + import java.io.OutputStream; ++import java.io.StringReader; + import java.io.UnsupportedEncodingException; + import java.lang.reflect.GenericArrayType; + import java.lang.reflect.ParameterizedType; +@@ -69,6 +70,7 @@ + + import org.apache.commons.logging.Log; + import org.apache.commons.logging.LogFactory; ++import org.xml.sax.EntityResolver; + import org.xml.sax.InputSource; + import org.xml.sax.SAXException; + import org.xml.sax.XMLReader; +@@ -668,8 +670,11 @@ + if (xmlReader == null) { + xmlReader = XMLReaderFactory.createXMLReader(); + } +- xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", +- this.processExternalEntities); ++ String name = "http://xml.org/sax/features/external-general-entities"; ++ xmlReader.setFeature(name, isProcessExternalEntities()); ++ if (!isProcessExternalEntities()) { ++ xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); ++ } + + return new SAXSource(xmlReader, inputSource); + } +@@ -865,4 +870,11 @@ + } + } + ++ ++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() { ++ public InputSource resolveEntity(String publicId, String systemId) { ++ return new InputSource(new StringReader("")); ++ } ++ }; ++ + } +--- a/projects/org.springframework.oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java ++++ b/projects/org.springframework.oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java +@@ -20,6 +20,7 @@ + import java.io.InputStream; + import java.io.OutputStream; + import java.io.Reader; ++import java.io.StringReader; + import java.io.Writer; + import javax.xml.parsers.DocumentBuilder; + import javax.xml.parsers.DocumentBuilderFactory; +@@ -42,6 +43,7 @@ + import org.apache.commons.logging.LogFactory; + import org.w3c.dom.Node; + import org.xml.sax.ContentHandler; ++import org.xml.sax.EntityResolver; + import org.xml.sax.InputSource; + import org.xml.sax.SAXException; + import org.xml.sax.XMLReader; +@@ -203,6 +205,9 @@ + protected XMLReader createXmlReader() throws SAXException { + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); ++ if (!isProcessExternalEntities()) { ++ xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); ++ } + return xmlReader; + } + +@@ -563,4 +568,11 @@ + protected abstract Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource) + throws XmlMappingException, IOException; + ++ ++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() { ++ public InputSource resolveEntity(String publicId, String systemId) { ++ return new InputSource(new StringReader("")); ++ } ++ }; ++ + } +--- a/projects/org.springframework.web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java ++++ b/projects/org.springframework.web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java +@@ -17,6 +17,7 @@ + package org.springframework.http.converter.xml; + + import java.io.IOException; ++import java.io.StringReader; + import javax.xml.bind.JAXBElement; + import javax.xml.bind.JAXBException; + import javax.xml.bind.MarshalException; +@@ -28,6 +29,8 @@ + import javax.xml.bind.annotation.XmlType; + import javax.xml.transform.Result; + import javax.xml.transform.Source; ++import javax.xml.transform.sax.SAXSource; ++import javax.xml.transform.stream.StreamSource; + + import org.springframework.core.annotation.AnnotationUtils; + import org.springframework.http.HttpHeaders; +@@ -36,6 +39,11 @@ + import org.springframework.http.converter.HttpMessageNotReadableException; + import org.springframework.http.converter.HttpMessageNotWritableException; + import org.springframework.util.ClassUtils; ++import org.xml.sax.EntityResolver; ++import org.xml.sax.InputSource; ++import org.xml.sax.SAXException; ++import org.xml.sax.XMLReader; ++import org.xml.sax.helpers.XMLReaderFactory; + + /** + * Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter} that can read +@@ -49,6 +57,21 @@ + */ + public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessageConverter<Object> { + ++ private boolean processExternalEntities = false; ++ ++ ++ /** ++ * Indicates whether external XML entities are processed when converting to a Source. ++ * <p>Default is {@code false}, meaning that external entities are not resolved. ++ */ ++ public void setProcessExternalEntities(boolean processExternalEntities) { ++ this.processExternalEntities = processExternalEntities; ++ } ++ ++ public boolean isProcessExternalEntities() { ++ return this.processExternalEntities; ++ } ++ + @Override + public boolean canRead(Class<?> clazz, MediaType mediaType) { + return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) && +@@ -69,6 +92,7 @@ + @Override + protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException { + try { ++ source = processSource(source); + Unmarshaller unmarshaller = createUnmarshaller(clazz); + if (clazz.isAnnotationPresent(XmlRootElement.class)) { + return unmarshaller.unmarshal(source); +@@ -87,6 +111,29 @@ + } + } + ++ protected Source processSource(Source source) { ++ if (source instanceof StreamSource) { ++ StreamSource streamSource = (StreamSource) source; ++ InputSource inputSource = new InputSource(streamSource.getInputStream()); ++ try { ++ XMLReader xmlReader = XMLReaderFactory.createXMLReader(); ++ String featureName = "http://xml.org/sax/features/external-general-entities"; ++ xmlReader.setFeature(featureName, isProcessExternalEntities()); ++ if (!isProcessExternalEntities()) { ++ xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); ++ } ++ return new SAXSource(xmlReader, inputSource); ++ } ++ catch (SAXException ex) { ++ logger.warn("Processing of external entities could not be disabled", ex); ++ return source; ++ } ++ } ++ else { ++ return source; ++ } ++ } ++ + @Override + protected void writeToResult(Object o, HttpHeaders headers, Result result) throws IOException { + try { +@@ -109,4 +156,11 @@ + } + } + ++ ++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() { ++ public InputSource resolveEntity(String publicId, String systemId) { ++ return new InputSource(new StringReader("")); ++ } ++ }; ++ + } +--- a/projects/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java ++++ b/projects/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java +@@ -21,9 +21,11 @@ + import java.io.IOException; + import java.io.InputStream; + import java.io.OutputStream; ++import java.io.StringReader; + import javax.xml.parsers.DocumentBuilder; + import javax.xml.parsers.DocumentBuilderFactory; + import javax.xml.parsers.ParserConfigurationException; ++import javax.xml.stream.XMLResolver; + import javax.xml.stream.XMLInputFactory; + import javax.xml.stream.XMLStreamException; + import javax.xml.stream.XMLStreamReader; +@@ -38,6 +40,7 @@ + import javax.xml.transform.stream.StreamSource; + + import org.w3c.dom.Document; ++import org.xml.sax.EntityResolver; + import org.xml.sax.InputSource; + import org.xml.sax.SAXException; + import org.xml.sax.XMLReader; +@@ -125,8 +128,11 @@ + try { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); +- documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", processExternalEntities); ++ documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); ++ if (!isProcessExternalEntities()) { ++ documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER); ++ } + Document document = documentBuilder.parse(body); + return new DOMSource(document); + } +@@ -141,8 +147,11 @@ + private SAXSource readSAXSource(InputStream body) throws IOException { + try { + XMLReader reader = XMLReaderFactory.createXMLReader(); +- reader.setFeature("http://xml.org/sax/features/external-general-entities", processExternalEntities); ++ reader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); + byte[] bytes = StreamUtils.copyToByteArray(body); ++ if (!isProcessExternalEntities()) { ++ reader.setEntityResolver(NO_OP_ENTITY_RESOLVER); ++ } + return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes))); + } + catch (SAXException ex) { +@@ -219,4 +228,17 @@ + } + } + ++ ++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() { ++ public InputSource resolveEntity(String publicId, String systemId) { ++ return new InputSource(new StringReader("")); ++ } ++ }; ++ ++ private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { ++ public Object resolveEntity(String publicID, String systemID, String base, String ns) { ++ return new ByteArrayInputStream(new byte[0]); ++ } ++ }; ++ + } +--- a/projects/org.springframework.web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTest.java ++++ b/projects/org.springframework.web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTest.java +@@ -98,6 +98,33 @@ + assertEquals("Invalid result", "Hello World", result.s); + } + ++ @Test ++ public void readXmlRootElementExternalEntityDisabled() throws Exception { ++ Resource external = new ClassPathResource("external.txt", getClass()); ++ String content = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" + ++ " <!ELEMENT external ANY >\n" + ++ " <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" + ++ " <rootElement><external>&ext;</external></rootElement>"; ++ MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8")); ++ RootElement rootElement = (RootElement) converter.read(RootElement.class, inputMessage); ++ ++ assertEquals("", rootElement.external); ++ } ++ ++ @Test ++ public void readXmlRootElementExternalEntityEnabled() throws Exception { ++ Resource external = new ClassPathResource("external.txt", getClass()); ++ String content = "<!DOCTYPE root [" + ++ " <!ELEMENT external ANY >\n" + ++ " <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" + ++ " <rootElement><external>&ext;</external></rootElement>"; ++ MockHttpInputMessage inputMessage = new MockHttpInputMessage(content.getBytes("UTF-8")); ++ this.converter.setProcessExternalEntities(true); ++ RootElement rootElement = (RootElement) converter.read(RootElement.class, inputMessage); ++ ++ assertEquals("Foo Bar", rootElement.external); ++ } ++ + @Test + public void writeXmlRootElement() throws Exception { + MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); +--- a/projects/org.springframework.web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java ++++ b/projects/org.springframework.web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java +@@ -67,9 +67,10 @@ + converter = new SourceHttpMessageConverter<Source>(); + Resource external = new ClassPathResource("external.txt", getClass()); + +- bodyExternal = "<!DOCTYPE root [" + +- " <!ELEMENT root ANY >\n" + +- " <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>"; ++ bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" + ++ " <!ELEMENT root ANY >\n" + ++ " <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>"; ++ + } + + @Test diff --git a/debian/patches/series b/debian/patches/series index 16c66b6..b41827d 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -12,3 +12,4 @@ CVE-2013-6429.patch CVE-2013-6430.patch CVE-2014-0054.patch CVE-2014-1904.patch +CVE-2014-0225.patch