From 42d97ced9ee7573509aa131e9037be4a8b196776 Mon Sep 17 00:00:00 2001 From: siyongchang Date: Tue, 23 Sep 2025 15:08:02 +0800 Subject: [PATCH] fix CVE-2022-46751 --- ...on-t-parse-doctypes-and-access-exter.patch | 1073 +++++++++++++++++ ...check-whether-properties-features-ca.patch | 95 ++ apache-ivy.spec | 7 +- 3 files changed, 1174 insertions(+), 1 deletion(-) create mode 100644 0001-CVE-2022-46751-don-t-parse-doctypes-and-access-exter.patch create mode 100644 0001-IVY-1647-better-check-whether-properties-features-ca.patch diff --git a/0001-CVE-2022-46751-don-t-parse-doctypes-and-access-exter.patch b/0001-CVE-2022-46751-don-t-parse-doctypes-and-access-exter.patch new file mode 100644 index 0000000..bf19ad1 --- /dev/null +++ b/0001-CVE-2022-46751-don-t-parse-doctypes-and-access-exter.patch @@ -0,0 +1,1073 @@ +From 2be17bc18b0e1d4123007d579e43ba1a4b6fab3d Mon Sep 17 00:00:00 2001 +From: Stefan Bodewig +Date: Sun, 22 Jan 2023 17:30:23 +0100 +Subject: [PATCH] CVE-2022-46751 don't parse doctypes and access external + entities by default + +--- + asciidoc/settings.adoc | 2 + + asciidoc/systemproperties.adoc | 67 +++ + asciidoc/toc.json | 5 + + .../org/apache/ivy/ant/IvyArtifactReport.java | 9 +- + src/java/org/apache/ivy/ant/IvyReport.java | 5 +- + .../ivy/core/settings/XmlSettingsParser.java | 9 +- + .../apache/ivy/osgi/obr/xml/OBRXMLWriter.java | 11 +- + .../ivy/plugins/parser/m2/PomReader.java | 3 +- + .../parser/xml/XmlModuleDescriptorParser.java | 69 ++- + .../ivy/plugins/report/XmlReportParser.java | 7 +- + src/java/org/apache/ivy/util/XMLHelper.java | 446 ++++++++++++++++-- + .../apache/ivy/core/resolve/ResolveTest.java | 39 ++ + 12 files changed, 605 insertions(+), 67 deletions(-) + create mode 100644 asciidoc/systemproperties.adoc + +diff --git a/asciidoc/settings.adoc b/asciidoc/settings.adoc +index c18c9a27..770794fc 100644 +--- a/asciidoc/settings.adoc ++++ b/asciidoc/settings.adoc +@@ -23,6 +23,8 @@ In order to work as you want, Ivy sometimes needs some settings. Actually, Ivy c + + Settings are specified through an XML file, usually called `ivysettings.xml`. To configure Ivy from Ant, you just have to use the link:use/settings{outfilesuffix}[settings] datatype with the path of your settings file. + ++In addition certain link:systemproperties{outfilesuffix}[Java system properties] affect the XML parsing behavior of Ivy. ++ + Here is an example of the settings file: + + [source, xml] +diff --git a/asciidoc/systemproperties.adoc b/asciidoc/systemproperties.adoc +new file mode 100644 +index 00000000..47592436 +--- /dev/null ++++ b/asciidoc/systemproperties.adoc +@@ -0,0 +1,67 @@ ++//// ++ 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 ++ ++ https://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. ++//// ++ ++= Java System Properties Affecting Ivy ++ ++== XML Parser Settings ++ ++Starting with Ivy 2.5.2 Ivy's XML parser can be controlled via the use ++of two newly introduced system properties. ++ ++If you want to restore the default behavior of Ivy 2.5.1 and earlier ++you need to set `ivy.xml.allow-doctype-processing` to `true` and ++`ivy.xml.external-resources` to `ALL`. ++ ++=== `ivy.xml.allow-doctype-processing` ++ ++This system property accepts `true` or `false` as values. When set to ++`false` Ivy will not allow any processing of doctype declarations at ++all, while setting it to `true` enables it. ++ ++The default is to allow doctype processing if and only if Ivy is ++parsing a Maven POM file. ++ ++=== `ivy.xml.external-resources` ++ ++This system property controls if external resources are read during ++doctype processing - and if so, where they can be loadad from. The ++value of this system property is only ever used if ++`ivy.xml.allow-doctype-processing` is not `false`. ++ ++The accepted values are ++ ++* `PROHIBIT` makes Ivy fail if any doctype tries to load an external ++ resource. ++* `IGNORE` makes Ivy ignore any external resource that the doctype ++ declaration wants to load. ++* `LOCAL_ONLY` allows external resources to be loaded via `file:` or ++ `jar:file` URIs only. ++* `ALL` allows external resources to be loaded from any URI. ++ ++The default behavior is to not allow doctype processing at all, but if ++it is enabled the value `PROHIBIT` is assumed unless the property has ++been set explicitly. ++ ++When reading Maven POMs a specific internal system id is recognized as ++resource and will be loaded from a resource shipping with the Ivy ++distribution in order to deal with invalid POM files accepted by ++Apache Maven - and the default value for this property is ++`IGNORE`in that case. See ++link:https://issues.apache.org/jira/browse/IVY-921[IVY-921] for ++details. +diff --git a/asciidoc/toc.json b/asciidoc/toc.json +index 2c8f1908..c6f6ec44 100644 +--- a/asciidoc/toc.json ++++ b/asciidoc/toc.json +@@ -150,6 +150,11 @@ + } + ] + }, ++ { ++ "id": "systemproperties", ++ "title": "System Properties", ++ "children": [] ++ }, + { + "id":"settings", + "title":"Settings Files", +diff --git a/src/java/org/apache/ivy/ant/IvyArtifactReport.java b/src/java/org/apache/ivy/ant/IvyArtifactReport.java +index 7e56348e..2e662658 100644 +--- a/src/java/org/apache/ivy/ant/IvyArtifactReport.java ++++ b/src/java/org/apache/ivy/ant/IvyArtifactReport.java +@@ -28,8 +28,6 @@ import java.util.Set; + + import javax.xml.transform.OutputKeys; + import javax.xml.transform.TransformerConfigurationException; +-import javax.xml.transform.TransformerFactoryConfigurationError; +-import javax.xml.transform.sax.SAXTransformerFactory; + import javax.xml.transform.sax.TransformerHandler; + import javax.xml.transform.stream.StreamResult; + +@@ -43,6 +41,7 @@ import org.apache.ivy.core.resolve.IvyNode; + import org.apache.ivy.core.resolve.ResolveOptions; + import org.apache.ivy.core.resolve.ResolvedModuleRevision; + import org.apache.ivy.core.retrieve.RetrieveOptions; ++import org.apache.ivy.util.XMLHelper; + import org.apache.tools.ant.BuildException; + import org.apache.tools.ant.Project; + import org.xml.sax.SAXException; +@@ -170,10 +169,8 @@ public class IvyArtifactReport extends IvyPostResolveTask { + } + + private TransformerHandler createTransformerHandler(FileOutputStream fileOutputStream) +- throws TransformerFactoryConfigurationError, TransformerConfigurationException { +- SAXTransformerFactory transformerFact = (SAXTransformerFactory) SAXTransformerFactory +- .newInstance(); +- TransformerHandler saxHandler = transformerFact.newTransformerHandler(); ++ throws TransformerConfigurationException { ++ TransformerHandler saxHandler = XMLHelper.getTransformerHandler(); + saxHandler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + saxHandler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); + saxHandler.setResult(new StreamResult(fileOutputStream)); +diff --git a/src/java/org/apache/ivy/ant/IvyReport.java b/src/java/org/apache/ivy/ant/IvyReport.java +index 662fd325..c3ba3836 100644 +--- a/src/java/org/apache/ivy/ant/IvyReport.java ++++ b/src/java/org/apache/ivy/ant/IvyReport.java +@@ -33,7 +33,6 @@ import javax.xml.transform.Source; + import javax.xml.transform.Transformer; + import javax.xml.transform.TransformerConfigurationException; + import javax.xml.transform.TransformerException; +-import javax.xml.transform.TransformerFactory; + import javax.xml.transform.stream.StreamResult; + import javax.xml.transform.stream.StreamSource; + +@@ -48,6 +47,7 @@ import org.apache.ivy.plugins.report.XmlReportOutputter; + import org.apache.ivy.plugins.report.XmlReportParser; + import org.apache.ivy.util.FileUtil; + import org.apache.ivy.util.Message; ++import org.apache.ivy.util.XMLHelper; + import org.apache.tools.ant.BuildException; + import org.apache.tools.ant.taskdefs.XSLTProcess; + import org.apache.tools.ant.util.JAXPUtils; +@@ -313,8 +313,7 @@ public class IvyReport extends IvyTask { + Source xsltSource = new StreamSource(xsltStream, JAXPUtils.getSystemId(style)); + + // create transformer +- TransformerFactory tFactory = TransformerFactory.newInstance(); +- Transformer transformer = tFactory.newTransformer(xsltSource); ++ Transformer transformer = XMLHelper.getTransformer(xsltSource); + + // add standard parameters + transformer.setParameter("confs", conf); +diff --git a/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java b/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java +index 0c743c9a..f791e699 100644 +--- a/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java ++++ b/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java +@@ -32,8 +32,6 @@ import java.util.HashMap; + import java.util.List; + import java.util.Map; + +-import javax.xml.parsers.SAXParserFactory; +- + import org.apache.ivy.core.IvyPatternHelper; + import org.apache.ivy.core.cache.RepositoryCacheManager; + import org.apache.ivy.core.module.status.StatusManager; +@@ -46,6 +44,7 @@ import org.apache.ivy.util.Checks; + import org.apache.ivy.util.Configurator; + import org.apache.ivy.util.FileResolver; + import org.apache.ivy.util.Message; ++import org.apache.ivy.util.XMLHelper; + import org.apache.ivy.util.url.CredentialsStore; + import org.apache.ivy.util.url.TimeoutConstrainedURLHandler; + import org.apache.ivy.util.url.URLHandlerRegistry; +@@ -151,10 +150,8 @@ public class XmlSettingsParser extends DefaultHandler { + @SuppressWarnings("deprecation") + private void doParse(URL settingsUrl) throws IOException, ParseException { + this.settings = settingsUrl; +- try (InputStream stream = URLHandlerRegistry.getDefault().openStream(settingsUrl)) { +- InputSource inSrc = new InputSource(stream); +- inSrc.setSystemId(settingsUrl.toExternalForm()); +- SAXParserFactory.newInstance().newSAXParser().parse(settingsUrl.toExternalForm(), this); ++ try { ++ XMLHelper.parse(settingsUrl, null, this); + ivy.validate(); + } catch (IOException e) { + throw e; +diff --git a/src/java/org/apache/ivy/osgi/obr/xml/OBRXMLWriter.java b/src/java/org/apache/ivy/osgi/obr/xml/OBRXMLWriter.java +index 41bf0760..fc5557f5 100644 +--- a/src/java/org/apache/ivy/osgi/obr/xml/OBRXMLWriter.java ++++ b/src/java/org/apache/ivy/osgi/obr/xml/OBRXMLWriter.java +@@ -22,9 +22,7 @@ import java.text.ParseException; + import java.util.Set; + + import javax.xml.transform.OutputKeys; +-import javax.xml.transform.Transformer; + import javax.xml.transform.TransformerConfigurationException; +-import javax.xml.transform.sax.SAXTransformerFactory; + import javax.xml.transform.sax.TransformerHandler; + import javax.xml.transform.stream.StreamResult; + +@@ -45,6 +43,7 @@ import org.apache.ivy.osgi.repo.ManifestAndLocation; + import org.apache.ivy.osgi.util.Version; + import org.apache.ivy.osgi.util.VersionRange; + import org.apache.ivy.util.Message; ++import org.apache.ivy.util.XMLHelper; + import org.xml.sax.ContentHandler; + import org.xml.sax.SAXException; + import org.xml.sax.helpers.AttributesImpl; +@@ -53,12 +52,10 @@ public class OBRXMLWriter { + + public static ContentHandler newHandler(OutputStream out, String encoding, boolean indent) + throws TransformerConfigurationException { +- SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); +- TransformerHandler hd = tf.newTransformerHandler(); +- Transformer serializer = tf.newTransformer(); ++ TransformerHandler hd = XMLHelper.getTransformerHandler(); ++ hd.getTransformer().setOutputProperty(OutputKeys.ENCODING, encoding); ++ hd.getTransformer().setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no"); + StreamResult stream = new StreamResult(out); +- serializer.setOutputProperty(OutputKeys.ENCODING, encoding); +- serializer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no"); + hd.setResult(stream); + return hd; + } +diff --git a/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java b/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java +index 88c9d70e..2bafc9b2 100644 +--- a/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java ++++ b/src/java/org/apache/ivy/plugins/parser/m2/PomReader.java +@@ -130,12 +130,13 @@ public class PomReader { + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + if (systemId != null && systemId.endsWith("m2-entities.ent")) { ++ // IVY-921: return an InputSource for our local packaged m2-entities.ent file + return new InputSource( + PomReader.class.getResourceAsStream("m2-entities.ent")); + } + return null; + } +- }); ++ }, true, XMLHelper.ExternalResources.IGNORE); + projectElement = pomDomDoc.getDocumentElement(); + if (!PROJECT.equals(projectElement.getNodeName()) + && !MODEL.equals(projectElement.getNodeName())) { +diff --git a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java +index 352cd7f3..532bcd2c 100644 +--- a/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java ++++ b/src/java/org/apache/ivy/plugins/parser/xml/XmlModuleDescriptorParser.java +@@ -17,9 +17,13 @@ + */ + package org.apache.ivy.plugins.parser.xml; + ++import java.io.BufferedReader; + import java.io.File; + import java.io.IOException; + import java.io.InputStream; ++import java.io.InputStreamReader; ++import java.io.StringReader; ++import java.io.UnsupportedEncodingException; + import java.net.MalformedURLException; + import java.net.URI; + import java.net.URISyntaxException; +@@ -80,6 +84,7 @@ import org.apache.ivy.util.Message; + import org.apache.ivy.util.XMLHelper; + import org.apache.ivy.util.extendable.ExtendableItemHelper; + import org.xml.sax.Attributes; ++import org.xml.sax.InputSource; + import org.xml.sax.SAXException; + + import static org.apache.ivy.core.module.descriptor.Configuration.Visibility.getVisibility; +@@ -216,6 +221,8 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser { + protected static final List ALLOWED_VERSIONS = Arrays.asList("1.0", + "1.1", "1.2", "1.3", "1.4", "2.0", "2.1", "2.2", "2.3", "2.4"); + ++ private static final String IVY_XSD_CONTENT; ++ + /* how and what do we have to parse */ + private ParserSettings settings; + +@@ -248,6 +255,40 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser { + + private Stack extraInfoStack = new Stack<>(); + ++ static { ++ String ivyXSDContent = null; ++ final InputStream is = Parser.class.getResourceAsStream("ivy.xsd"); ++ if (is != null) { ++ final StringBuilder sb = new StringBuilder(); ++ try { ++ try { ++ final BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); ++ String line = null; ++ while ((line = reader.readLine()) != null) { ++ if (sb.length() != 0) { ++ sb.append("\n"); ++ } ++ sb.append(line); ++ } ++ } catch (UnsupportedEncodingException e) { ++ // ignore ++ ivyXSDContent = null; ++ } catch (IOException e) { ++ // ignore ++ ivyXSDContent = null; ++ } ++ } finally { ++ try { ++ is.close(); ++ } catch (Exception e) { ++ // ignore ++ } ++ } ++ ivyXSDContent = sb.length() == 0 ? null : sb.toString(); ++ } ++ IVY_XSD_CONTENT = ivyXSDContent; ++ } ++ + public Parser(ModuleDescriptorParser parser, ParserSettings ivySettings) { + super(parser); + settings = ivySettings; +@@ -268,10 +309,14 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser { + public void parse() throws ParseException { + try { + URL schemaURL = validate ? getSchemaURL() : null; ++ XMLHelper.ExternalResources e = ++ validate && System.getProperty(XMLHelper.EXTERNAL_RESOURCES) == null ++ ? XMLHelper.ExternalResources.IGNORE ++ : XMLHelper.ExternalResources.fromSystemProperty(); + if (descriptorURL != null) { +- XMLHelper.parse(descriptorURL, schemaURL, this); ++ XMLHelper.parse(descriptorURL, schemaURL, this, null, e); + } else { +- XMLHelper.parse(descriptorInput, schemaURL, this, null); ++ XMLHelper.parse(descriptorInput, schemaURL, this, null, e); + } + checkConfigurations(); + replaceConfigurationWildcards(); +@@ -296,6 +341,26 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser { + } + } + ++ @Override ++ public InputSource resolveEntity(final String publicId, final String systemId) ++ throws IOException, SAXException { ++ if (isApacheOrgIvyXSDSystemId(systemId) && IVY_XSD_CONTENT != null) { ++ // redirect the schema location to local file based ivy.xsd whose content ++ // we have already read and is available in-memory. ++ final InputSource source = new InputSource(new StringReader(IVY_XSD_CONTENT)); ++ return source; ++ } ++ return super.resolveEntity(publicId, systemId); ++ } ++ ++ private static boolean isApacheOrgIvyXSDSystemId(final String systemId) { ++ if (systemId == null) { ++ return false; ++ } ++ return systemId.equals("http://ant.apache.org/ivy/schemas/ivy.xsd") ++ || systemId.equals("https://ant.apache.org/ivy/schemas/ivy.xsd"); ++ } ++ + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { +diff --git a/src/java/org/apache/ivy/plugins/report/XmlReportParser.java b/src/java/org/apache/ivy/plugins/report/XmlReportParser.java +index b35c4833..e791cf09 100644 +--- a/src/java/org/apache/ivy/plugins/report/XmlReportParser.java ++++ b/src/java/org/apache/ivy/plugins/report/XmlReportParser.java +@@ -27,9 +27,6 @@ import java.util.Map; + import java.util.SortedMap; + import java.util.TreeMap; + +-import javax.xml.parsers.SAXParser; +-import javax.xml.parsers.SAXParserFactory; +- + import org.apache.ivy.core.cache.ArtifactOrigin; + import org.apache.ivy.core.module.descriptor.Artifact; + import org.apache.ivy.core.module.descriptor.DefaultArtifact; +@@ -38,6 +35,7 @@ import org.apache.ivy.core.report.ArtifactDownloadReport; + import org.apache.ivy.core.report.DownloadStatus; + import org.apache.ivy.core.report.MetadataArtifactDownloadReport; + import org.apache.ivy.util.DateUtil; ++import org.apache.ivy.util.XMLHelper; + import org.apache.ivy.util.extendable.ExtendableItemHelper; + import org.xml.sax.Attributes; + import org.xml.sax.SAXException; +@@ -242,8 +240,7 @@ public class XmlReportParser { + } + + public void parse() throws Exception { +- SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); +- saxParser.parse(report, new XmlReportParserHandler()); ++ XMLHelper.parse(report.toURI().toURL(), null, new XmlReportParserHandler()); + } + + private static boolean parseBoolean(String str) { +diff --git a/src/java/org/apache/ivy/util/XMLHelper.java b/src/java/org/apache/ivy/util/XMLHelper.java +index 57373687..e5bfa7be 100644 +--- a/src/java/org/apache/ivy/util/XMLHelper.java ++++ b/src/java/org/apache/ivy/util/XMLHelper.java +@@ -19,6 +19,7 @@ package org.apache.ivy.util; + + import java.io.IOException; + import java.io.InputStream; ++import java.io.StringReader; + import java.net.URI; + import java.net.URISyntaxException; + import java.net.URL; +@@ -28,13 +29,24 @@ import javax.xml.parsers.DocumentBuilderFactory; + import javax.xml.parsers.ParserConfigurationException; + import javax.xml.parsers.SAXParser; + import javax.xml.parsers.SAXParserFactory; ++import javax.xml.transform.Source; ++import javax.xml.transform.Transformer; ++import javax.xml.transform.TransformerConfigurationException; ++import javax.xml.transform.TransformerFactory; ++import javax.xml.transform.sax.SAXTransformerFactory; ++import javax.xml.transform.sax.TransformerHandler; + + import org.apache.ivy.util.url.URLHandlerRegistry; + import org.w3c.dom.Document; ++import org.xml.sax.Attributes; + import org.xml.sax.EntityResolver; + import org.xml.sax.InputSource; ++import org.xml.sax.Locator; + import org.xml.sax.SAXException; + import org.xml.sax.SAXNotRecognizedException; ++import org.xml.sax.SAXNotSupportedException; ++import org.xml.sax.SAXParseException; ++import org.xml.sax.XMLReader; + import org.xml.sax.ext.LexicalHandler; + import org.xml.sax.helpers.DefaultHandler; + +@@ -50,49 +62,38 @@ public abstract class XMLHelper { + + static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; + +- private static boolean canUseSchemaValidation = true; ++ private static final String XML_ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema"; ++ private static final String XML_ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD"; ++ public static final String ALLOW_DOCTYPE_PROCESSING = "ivy.xml.allow-doctype-processing"; ++ public static final String EXTERNAL_RESOURCES = "ivy.xml.external-resources"; + +- private static Boolean canDisableExternalDtds = null; +- +- private static SAXParser newSAXParser(URL schema, InputStream schemaStream, +- boolean loadExternalDtds) throws ParserConfigurationException, SAXException { +- SAXParserFactory parserFactory = SAXParserFactory.newInstance(); ++ private static SAXParser newSAXParser(final URL schema, final InputStream schemaStream, ++ final boolean allowXmlDoctypeProcessing, final ExternalResources externalResources) ++ throws ParserConfigurationException, SAXException { ++ final SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); +- parserFactory.setValidating(canUseSchemaValidation && (schema != null)); +- if (!loadExternalDtds && canDisableExternalDtds(parserFactory)) { +- parserFactory.setFeature(XERCES_LOAD_EXTERNAL_DTD, false); +- } +- SAXParser parser = parserFactory.newSAXParser(); ++ parserFactory.setValidating(schema != null); ++ configureSafeFeatures(parserFactory, allowXmlDoctypeProcessing, externalResources); + +- if (canUseSchemaValidation && schema != null) { ++ SAXParser parser = parserFactory.newSAXParser(); ++ if (schema != null) { + try { + parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); + parser.setProperty(JAXP_SCHEMA_SOURCE, schemaStream); + } catch (SAXNotRecognizedException ex) { + Message.warn("problem while setting JAXP validating property on SAXParser... " + + "XML validation will not be done", ex); +- canUseSchemaValidation = false; + parserFactory.setValidating(false); + parser = parserFactory.newSAXParser(); + } + } +- +- parser.getXMLReader().setFeature(XML_NAMESPACE_PREFIXES, true); ++ final XMLReader reader = parser.getXMLReader(); ++ reader.setFeature(XML_NAMESPACE_PREFIXES, true); ++ reader.setProperty(XML_ACCESS_EXTERNAL_SCHEMA, externalResources.getAllowedProtocols()); ++ reader.setProperty(XML_ACCESS_EXTERNAL_DTD, externalResources.getAllowedProtocols()); + return parser; + } + +- private static boolean canDisableExternalDtds(SAXParserFactory parserFactory) { +- if (canDisableExternalDtds == null) { +- try { +- parserFactory.getFeature(XERCES_LOAD_EXTERNAL_DTD); +- canDisableExternalDtds = Boolean.TRUE; +- } catch (Exception ex) { +- canDisableExternalDtds = Boolean.FALSE; +- } +- } +- return canDisableExternalDtds; +- } +- + /** + * Convert an URL to a valid systemId according to RFC 2396. + * +@@ -116,36 +117,58 @@ public abstract class XMLHelper { + parse(xmlURL, schema, handler, null); + } + +- @SuppressWarnings("deprecation") + public static void parse(URL xmlURL, URL schema, DefaultHandler handler, LexicalHandler lHandler) + throws SAXException, IOException, ParserConfigurationException { ++ parse(xmlURL, schema, handler, lHandler, ExternalResources.fromSystemProperty()); ++ } ++ ++ @SuppressWarnings("deprecation") ++ public static void parse(URL xmlURL, URL schema, DefaultHandler handler, LexicalHandler lHandler, ++ final ExternalResources externalResources) ++ throws SAXException, IOException, ParserConfigurationException { + try (InputStream xmlStream = URLHandlerRegistry.getDefault().openStream(xmlURL)) { + InputSource inSrc = new InputSource(xmlStream); + inSrc.setSystemId(toSystemId(xmlURL)); +- parse(inSrc, schema, handler, lHandler); ++ parse(inSrc, schema, handler, lHandler, externalResources); + } + } + + public static void parse(InputStream xmlStream, URL schema, DefaultHandler handler, + LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException { ++ parse(xmlStream, schema, handler, lHandler, ExternalResources.fromSystemProperty()); ++ } ++ ++ public static void parse(InputStream xmlStream, URL schema, DefaultHandler handler, ++ LexicalHandler lHandler, final ExternalResources externalResources) ++ throws SAXException, IOException, ParserConfigurationException { + parse(new InputSource(xmlStream), schema, handler, lHandler); + } + + public static void parse(InputSource xmlStream, URL schema, DefaultHandler handler, + LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException { +- parse(xmlStream, schema, handler, lHandler, true); ++ parse(xmlStream, schema, handler, lHandler, ExternalResources.fromSystemProperty()); ++ } ++ ++ public static void parse(final InputSource xmlStream, final URL schema, ++ final DefaultHandler handler, final LexicalHandler lHandler, ++ final boolean loadExternalDtds) throws SAXException, IOException, ++ ParserConfigurationException { ++ parse(xmlStream, schema, handler, lHandler, ++ loadExternalDtds ? ExternalResources.LOCAL_ONLY : ExternalResources.PROHIBIT); + } + + @SuppressWarnings("deprecation") +- public static void parse(InputSource xmlStream, URL schema, DefaultHandler handler, +- LexicalHandler lHandler, boolean loadExternalDtds) throws SAXException, IOException, ++ public static void parse(final InputSource xmlStream, final URL schema, ++ final DefaultHandler handler, final LexicalHandler lHandler, ++ final ExternalResources externalResources) throws SAXException, IOException, + ParserConfigurationException { + InputStream schemaStream = null; + try { + if (schema != null) { + schemaStream = URLHandlerRegistry.getDefault().openStream(schema); + } +- SAXParser parser = XMLHelper.newSAXParser(schema, schemaStream, loadExternalDtds); ++ SAXParser parser = XMLHelper.newSAXParser(schema, schemaStream, ++ isXmlDoctypeProcessingAllowed(), externalResources); + + if (lHandler != null) { + try { +@@ -157,7 +180,10 @@ public abstract class XMLHelper { + } + } + +- parser.parse(xmlStream, handler); ++ DefaultHandler h = externalResources == ExternalResources.IGNORE ++ ? new NoopEntityResolverDefaultHandler(handler) ++ : handler; ++ parser.parse(xmlStream, h); + } finally { + if (schemaStream != null) { + try { +@@ -170,7 +196,7 @@ public abstract class XMLHelper { + } + + public static boolean canUseSchemaValidation() { +- return canUseSchemaValidation; ++ return true; + } + + /** +@@ -216,15 +242,33 @@ public abstract class XMLHelper { + + public static Document parseToDom(InputSource source, EntityResolver entityResolver) + throws IOException, SAXException { +- DocumentBuilder docBuilder = getDocBuilder(entityResolver); ++ return parseToDom(source, entityResolver, isXmlDoctypeProcessingAllowed(), ++ ExternalResources.fromSystemProperty()); ++ } ++ ++ public static Document parseToDom(InputSource source, EntityResolver entityResolver, ++ boolean allowXmlDoctypeProcessing, ExternalResources externalResources) ++ throws IOException, SAXException { ++ DocumentBuilder docBuilder = getDocBuilder(entityResolver, allowXmlDoctypeProcessing, ++ externalResources); + return docBuilder.parse(source); + } + + public static DocumentBuilder getDocBuilder(EntityResolver entityResolver) { ++ return getDocBuilder(entityResolver, isXmlDoctypeProcessingAllowed(), ++ ExternalResources.fromSystemProperty()); ++ } ++ ++ public static DocumentBuilder getDocBuilder(EntityResolver entityResolver, ++ boolean allowXmlDoctypeProcessing, ExternalResources externalResources) { + try { +- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); ++ final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating(false); ++ configureSafeFeatures(factory, allowXmlDoctypeProcessing, externalResources); + DocumentBuilder docBuilder = factory.newDocumentBuilder(); ++ if (externalResources == ExternalResources.IGNORE) { ++ entityResolver = new NoopEntityResolver(entityResolver); ++ } + if (entityResolver != null) { + docBuilder.setEntityResolver(entityResolver); + } +@@ -234,7 +278,335 @@ public abstract class XMLHelper { + } + } + ++ public static Transformer getTransformer(Source source) throws TransformerConfigurationException { ++ TransformerFactory factory = getTransformerFactory(); ++ return factory.newTransformer(source); ++ } ++ ++ public static TransformerHandler getTransformerHandler() throws TransformerConfigurationException { ++ SAXTransformerFactory factory = getTransformerFactory(); ++ return factory.newTransformerHandler(); ++ } ++ ++ public enum ExternalResources { ++ PROHIBIT(""), ++ // technically the URIs for IGNORE will never get resolved at all. ++ // "all" pacifies some version of Java that check the property before delegating to the EntityResolver (which is ++ // going to return an empty content anyway) ++ IGNORE("all"), ++ LOCAL_ONLY("file, jar:file"), ++ ALL("all"); ++ ++ private final String allowedProtocols; ++ ++ private ExternalResources(String allowedProtocols) { ++ this.allowedProtocols = allowedProtocols; ++ } ++ ++ private String getAllowedProtocols() { ++ return allowedProtocols; ++ } ++ ++ public static ExternalResources fromSystemProperty() { ++ final String val = System.getProperty(EXTERNAL_RESOURCES); ++ if (val != null) { ++ if (val.equalsIgnoreCase("ignore")) { ++ return IGNORE; ++ } ++ if (val.equalsIgnoreCase("all")) { ++ return ALL; ++ } ++ if (val.equalsIgnoreCase("local-only") || val.equalsIgnoreCase("local_only")) { ++ return LOCAL_ONLY; ++ } ++ } ++ return PROHIBIT; ++ } ++ } ++ ++ public static boolean isXmlDoctypeProcessingAllowed() { ++ return "true".equals(System.getProperty(ALLOW_DOCTYPE_PROCESSING)); ++ } ++ + private XMLHelper() { + } + ++ private static SAXTransformerFactory getTransformerFactory() { ++ TransformerFactory factory = SAXTransformerFactory.newInstance(); ++ configureSafeFeatures(factory); ++ return (SAXTransformerFactory) factory; ++ } ++ ++ private static void configureSafeFeatures(final DocumentBuilderFactory factory, ++ final boolean allowXmlDoctypeProcessing, final ExternalResources externalResources) { ++ final String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl"; ++ trySetFeature(factory, DISALLOW_DOCTYPE_DECL, !allowXmlDoctypeProcessing); ++ ++ // available since Java 6, as XMLConstants.FEATURE_SECURE_PROCESSING. We can't use Java 6 ++ // at compile time, in current version, so inline the constant here ++ final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing"; ++ trySetFeature(factory, FEATURE_SECURE_PROCESSING, true); ++ ++ final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities"; ++ trySetFeature(factory, ALLOW_EXTERNAL_GENERAL_ENTITIES, false); ++ ++ final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities"; ++ trySetFeature(factory, ALLOW_EXTERNAL_PARAM_ENTITIES, false); ++ ++ final String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; ++ trySetFeature(factory, LOAD_EXTERNAL_DTD, externalResources != ExternalResources.PROHIBIT); ++ ++ try { ++ factory.setXIncludeAware(false); ++ } catch (Exception e) { ++ // ignore ++ } ++ try { ++ factory.setExpandEntityReferences(false); ++ } catch (Exception e) { ++ // ignore ++ } ++ } ++ ++ private static void configureSafeFeatures(final SAXParserFactory factory, ++ final boolean allowXmlDoctypeProcessing, final ExternalResources externalResources) { ++ final String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl"; ++ trySetFeature(factory, DISALLOW_DOCTYPE_DECL, !allowXmlDoctypeProcessing); ++ ++ // available since Java 6, as XMLConstants.FEATURE_SECURE_PROCESSING. We can't use Java 6 ++ // at compile time, in current version, so inline the constant here ++ final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing"; ++ trySetFeature(factory, FEATURE_SECURE_PROCESSING, true); ++ ++ final boolean allowEntities = externalResources == ExternalResources.LOCAL_ONLY ++ || externalResources == ExternalResources.ALL; ++ final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities"; ++ trySetFeature(factory, ALLOW_EXTERNAL_GENERAL_ENTITIES, allowEntities); ++ ++ final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities"; ++ trySetFeature(factory, ALLOW_EXTERNAL_PARAM_ENTITIES, allowEntities); ++ final String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; ++ trySetFeature(factory, LOAD_EXTERNAL_DTD, externalResources != ExternalResources.PROHIBIT); ++ try { ++ factory.setXIncludeAware(false); ++ } catch (Exception e) { ++ // ignore ++ } ++ } ++ ++ private static void configureSafeFeatures(final TransformerFactory factory) { ++ // available since Java 7, as XMLConstants.ACCESS_EXTERNAL_DTD, ACCESS_EXTERNAL_SCHEMA and ++ // ACCESS_EXTERNAL_STYLESHEET respectively. ++ // We can't use Java 7 at compile time, in current version, so inline the constants here ++ trySetAttribute(factory, XML_ACCESS_EXTERNAL_DTD, ""); ++ trySetAttribute(factory, XML_ACCESS_EXTERNAL_SCHEMA, ""); ++ trySetAttribute(factory, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); ++ } ++ ++ private static boolean isFeatureSupported(final SAXParserFactory factory, final String feature) { ++ try { ++ factory.getFeature(feature); ++ return true; ++ } catch (ParserConfigurationException e) { ++ return false; ++ } catch (SAXNotRecognizedException e) { ++ return false; ++ } catch (SAXNotSupportedException e) { ++ return false; ++ } ++ } ++ ++ private static boolean isFeatureSupported(final DocumentBuilderFactory factory, final String feature) { ++ try { ++ factory.getFeature(feature); ++ return true; ++ } catch (ParserConfigurationException e) { ++ return false; ++ } ++ } ++ ++ private static boolean isAttributeSupported(final TransformerFactory factory, final String attribute) { ++ try { ++ factory.getAttribute(attribute); ++ return true; ++ } catch (IllegalArgumentException e) { ++ return false; ++ } ++ } ++ ++ private static boolean trySetFeature(final DocumentBuilderFactory factory, ++ final String feature, final boolean val) { ++ if (!isFeatureSupported(factory, feature)) { ++ return false; ++ } ++ try { ++ factory.setFeature(feature, val); ++ return true; ++ } catch (ParserConfigurationException e) { ++ // log and continue ++ Message.warn("Failed to set feature " + feature + " on DocumentBuilderFactory", e); ++ return false; ++ } ++ } ++ ++ private static boolean trySetFeature(final SAXParserFactory factory, ++ final String feature, final boolean val) { ++ if (!isFeatureSupported(factory, feature)) { ++ return false; ++ } ++ try { ++ factory.setFeature(feature, val); ++ return true; ++ } catch (ParserConfigurationException e) { ++ // log and continue ++ Message.warn("Failed to set feature " + feature + " on SAXParserFactory", e); ++ return false; ++ } catch (SAXNotRecognizedException e) { ++ // log and continue ++ Message.warn("Failed to set feature " + feature + " on SAXParserFactory", e); ++ return false; ++ } catch (SAXNotSupportedException e) { ++ // log and continue ++ Message.warn("Failed to set feature " + feature + " on SAXParserFactory", e); ++ return false; ++ } ++ } ++ ++ private static boolean trySetAttribute(final TransformerFactory factory, ++ final String attribute, final String val) { ++ if (!isAttributeSupported(factory, attribute)) { ++ return false; ++ } ++ try { ++ factory.setAttribute(attribute, val); ++ return true; ++ } catch (IllegalArgumentException e) { ++ // log and continue ++ Message.warn("Failed to set attribute " + attribute + " on TransformerFactory", e); ++ return false; ++ } ++ } ++ ++ private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new StringReader("")); ++ ++ private static class NoopEntityResolver implements EntityResolver { ++ private EntityResolver wrapped; ++ ++ private NoopEntityResolver(EntityResolver wrapped) { ++ this.wrapped = wrapped; ++ } ++ ++ @Override ++ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { ++ if (wrapped != null) { ++ InputSource s = wrapped.resolveEntity(publicId, systemId); ++ if (s != null) { ++ return s; ++ } ++ } ++ return EMPTY_INPUT_SOURCE; ++ } ++ } ++ ++ private static class NoopEntityResolverDefaultHandler extends DefaultHandler { ++ ++ private DefaultHandler wrapped; ++ ++ private NoopEntityResolverDefaultHandler(DefaultHandler wrapped) { ++ this.wrapped = wrapped; ++ } ++ ++ @Override ++ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { ++ if (wrapped != null) { ++ InputSource s = wrapped.resolveEntity(publicId, systemId); ++ if (s != null) { ++ return s; ++ } ++ } ++ return EMPTY_INPUT_SOURCE; ++ } ++ ++ @Override ++ public void notationDecl(String name, String publicId, String systemId) throws SAXException { ++ wrapped.notationDecl(name, publicId, systemId); ++ } ++ ++ @Override ++ public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName) ++ throws SAXException { ++ wrapped.unparsedEntityDecl(name, publicId, systemId, notationName); ++ } ++ ++ @Override ++ public void setDocumentLocator(Locator locator) { ++ wrapped.setDocumentLocator(locator); ++ } ++ ++ @Override ++ public void startDocument() throws SAXException { ++ wrapped.startDocument(); ++ } ++ ++ @Override ++ public void endDocument() throws SAXException { ++ wrapped.endDocument(); ++ } ++ ++ @Override ++ public void startPrefixMapping(String prefix, String uri) throws SAXException { ++ wrapped.startPrefixMapping(prefix, uri); ++ } ++ ++ @Override ++ public void endPrefixMapping(String prefix) throws SAXException { ++ wrapped.endPrefixMapping(prefix); ++ } ++ ++ @Override ++ public void startElement(String uri, String localName, String qName, Attributes attributes) ++ throws SAXException { ++ wrapped.startElement(uri, localName, qName, attributes); ++ } ++ ++ @Override ++ public void endElement(String uri, String localName, String qName) throws SAXException { ++ wrapped.endElement(uri, localName, qName); ++ } ++ ++ @Override ++ public void characters(char[] ch, int start, int length) throws SAXException { ++ wrapped.characters(ch, start, length); ++ } ++ ++ @Override ++ public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { ++ wrapped.ignorableWhitespace(ch, start, length); ++ } ++ ++ @Override ++ public void processingInstruction(String target, String data) throws SAXException { ++ wrapped.processingInstruction(target, data); ++ } ++ ++ @Override ++ public void skippedEntity(String name) throws SAXException { ++ wrapped.skippedEntity(name); ++ } ++ ++ @Override ++ public void warning(SAXParseException e) throws SAXException { ++ wrapped.warning(e); ++ } ++ ++ @Override ++ public void error(SAXParseException e) throws SAXException { ++ wrapped.error(e); ++ } ++ ++ @Override ++ public void fatalError(SAXParseException e) throws SAXException { ++ wrapped.fatalError(e); ++ } ++ } + } +diff --git a/test/java/org/apache/ivy/core/resolve/ResolveTest.java b/test/java/org/apache/ivy/core/resolve/ResolveTest.java +index 633ca646..5c611420 100644 +--- a/test/java/org/apache/ivy/core/resolve/ResolveTest.java ++++ b/test/java/org/apache/ivy/core/resolve/ResolveTest.java +@@ -51,6 +51,7 @@ import org.apache.ivy.plugins.resolver.FileSystemResolver; + import org.apache.ivy.util.CacheCleaner; + import org.apache.ivy.util.FileUtil; + import org.apache.ivy.util.MockMessageLogger; ++import org.apache.ivy.util.XMLHelper; + import org.junit.After; + import org.junit.Assert; + import org.junit.Before; +@@ -74,6 +75,7 @@ import java.util.HashMap; + import java.util.HashSet; + import java.util.List; + import java.util.Map; ++import java.util.Properties; + import java.util.Set; + import java.util.jar.JarEntry; + import java.util.jar.JarFile; +@@ -309,20 +311,57 @@ public class ResolveTest { + + @Test + public void testResolveWithXmlEntities() { ++ testResolveWithXmlEntities(null, 0); ++ testResolveWithXmlEntities("prohibit", 0); ++ testResolveWithXmlEntities("ignore", 0); ++ testResolveWithXmlEntities("local-only", 2); ++ testResolveWithXmlEntities("LOCAL_ONLY", 2); ++ testResolveWithXmlEntities("all", 2); ++ } ++ ++ private void testResolveWithXmlEntities(String externalResourcesSystemProperty, ++ int expectedNumberOfDependencies) { + Ivy ivy = new Ivy(); + Throwable th = null; ++ Properties p = System.getProperties(); + try { ++ System.setProperties(new Properties()); ++ System.setProperty(XMLHelper.ALLOW_DOCTYPE_PROCESSING, "true"); ++ if (externalResourcesSystemProperty != null) { ++ System.setProperty(XMLHelper.EXTERNAL_RESOURCES, externalResourcesSystemProperty); ++ } + ivy.configure(new File("test/repositories/xml-entities/ivysettings.xml")); + ResolveReport report = ivy.resolve(new File("test/repositories/xml-entities/ivy.xml"), + getResolveOptions(new String[] {"*"})); + assertNotNull(report); + assertFalse(report.hasError()); ++ assertNotNull(report.getDependencies()); ++ assertEquals("number of dependencies while setting " + externalResourcesSystemProperty, ++ expectedNumberOfDependencies, report.getDependencies().size()); + } catch (Throwable e) { + th = e; ++ } finally { ++ System.setProperties(p); + } + assertNull(th); + } + ++ @Test ++ public void testResolveWithXmlEntitiesButNoSystemProperty() { ++ Ivy ivy = new Ivy(); ++ Throwable th = null; ++ try { ++ ivy.configure(new File("test/repositories/xml-entities/ivysettings.xml")); ++ ResolveReport report = ivy.resolve(new File("test/repositories/xml-entities/ivy.xml"), ++ getResolveOptions(new String[] {"*"})); ++ assertNotNull(report); ++ assertFalse(report.hasError()); ++ } catch (Throwable e) { ++ th = e; ++ } ++ assertNotNull(th); ++ } ++ + @Test + public void testResolveNoRevisionInPattern() throws Exception { + // module1 depends on latest version of module2, for which there is no revision in the +-- +2.43.5 + diff --git a/0001-IVY-1647-better-check-whether-properties-features-ca.patch b/0001-IVY-1647-better-check-whether-properties-features-ca.patch new file mode 100644 index 0000000..08b9232 --- /dev/null +++ b/0001-IVY-1647-better-check-whether-properties-features-ca.patch @@ -0,0 +1,95 @@ +diff --git a/src/java/org/apache/ivy/util/XMLHelper.java b/src/java/org/apache/ivy/util/XMLHelper.java +index e5bfa7be..9fc740ac 100644 +--- a/src/java/org/apache/ivy/util/XMLHelper.java ++++ b/src/java/org/apache/ivy/util/XMLHelper.java +@@ -88,9 +88,11 @@ public abstract class XMLHelper { + } + } + final XMLReader reader = parser.getXMLReader(); +- reader.setFeature(XML_NAMESPACE_PREFIXES, true); +- reader.setProperty(XML_ACCESS_EXTERNAL_SCHEMA, externalResources.getAllowedProtocols()); +- reader.setProperty(XML_ACCESS_EXTERNAL_DTD, externalResources.getAllowedProtocols()); ++ trySetFeature(reader, XML_NAMESPACE_PREFIXES, true); ++ trySetProperty(reader, XML_ACCESS_EXTERNAL_SCHEMA, ++ externalResources.getAllowedProtocols()); ++ trySetProperty(reader, XML_ACCESS_EXTERNAL_DTD, ++ externalResources.getAllowedProtocols()); + return parser; + } + +@@ -425,6 +427,15 @@ public abstract class XMLHelper { + } + } + ++ private static boolean isFeatureSupported(final XMLReader reader, final String feature) { ++ try { ++ reader.getFeature(feature); ++ return true; ++ } catch (SAXException e) { ++ return false; ++ } ++ } ++ + private static boolean isAttributeSupported(final TransformerFactory factory, final String attribute) { + try { + factory.getAttribute(attribute); +@@ -434,6 +445,15 @@ public abstract class XMLHelper { + } + } + ++ private static boolean isPropertySupported(final XMLReader reader, final String property) { ++ try { ++ reader.getProperty(property); ++ return true; ++ } catch (SAXException e) { ++ return false; ++ } ++ } ++ + private static boolean trySetFeature(final DocumentBuilderFactory factory, + final String feature, final boolean val) { + if (!isFeatureSupported(factory, feature)) { +@@ -472,6 +492,21 @@ public abstract class XMLHelper { + } + } + ++ private static boolean trySetFeature(final XMLReader reader, ++ final String feature, final boolean val) { ++ if (!isFeatureSupported(reader, feature)) { ++ return false; ++ } ++ try { ++ reader.setFeature(feature, val); ++ return true; ++ } catch (SAXException e) { ++ // log and continue ++ Message.warn("Failed to set feature " + feature + " on XMLReader", e); ++ return false; ++ } ++ } ++ + private static boolean trySetAttribute(final TransformerFactory factory, + final String attribute, final String val) { + if (!isAttributeSupported(factory, attribute)) { +@@ -487,6 +522,21 @@ public abstract class XMLHelper { + } + } + ++ private static boolean trySetProperty(final XMLReader reader, ++ final String property, final Object val) { ++ if (!isPropertySupported(reader, property)) { ++ return false; ++ } ++ try { ++ reader.setProperty(property, val); ++ return true; ++ } catch (SAXException e) { ++ // log and continue ++ Message.warn("Failed to set property " + property + " on XMLReader", e); ++ return false; ++ } ++ } ++ + private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new StringReader("")); + + private static class NoopEntityResolver implements EntityResolver { diff --git a/apache-ivy.spec b/apache-ivy.spec index 631d40a..8d4aa76 100644 --- a/apache-ivy.spec +++ b/apache-ivy.spec @@ -5,13 +5,15 @@ Name: apache-ivy Version: 2.5.1 -Release: 1 +Release: 2 Summary: Java-based dependency manager License: Apache-2.0 URL: https://ant.apache.org/ivy/ Source0: http://archive.apache.org/dist/ant/ivy/%{version}/%{name}-%{version}-src.tar.gz Patch1: apache-ivy-global-settings.patch +Patch2: 0001-CVE-2022-46751-don-t-parse-doctypes-and-access-exter.patch +Patch3: 0001-IVY-1647-better-check-whether-properties-features-ca.patch BuildArch: noarch BuildRequires: gnupg2 BuildRequires: ant @@ -125,6 +127,9 @@ echo "apache-ivy/ivy" > %{buildroot}%{_sysconfdir}/ant.d/%{name} %doc README.adoc NOTICE %changelog +* Tue Sep 23 2025 siyongchang - 2.5.1-2 +- fix CVE-2022-46751 + * Tue May 27 2025 yaoxin <1024769339@qq.com> - 2.5.1-1 - Due to apache-ivy 2.5.2 and later version don't parse doctypes and access external entities by default, downgrade to 2.5.1 to fix forbidden-apis build failure -- Gitee