From a97b64544878470eb4646e5929eaa481742b5ff4 Mon Sep 17 00:00:00 2001 From: starlet-dx <15929766099@163.com> Date: Tue, 12 Oct 2021 16:16:27 +0800 Subject: [PATCH] fix CVE-2021-41098 (cherry picked from commit 8eb94a018904040e4558d73badcbc07e089e0cc2) --- CVE-2021-41098-1.patch | 684 +++++++++++++++++++++++++++++++++++++++++ CVE-2021-41098-2.patch | 28 ++ rubygem-nokogiri.spec | 14 +- 3 files changed, 725 insertions(+), 1 deletion(-) create mode 100644 CVE-2021-41098-1.patch create mode 100644 CVE-2021-41098-2.patch diff --git a/CVE-2021-41098-1.patch b/CVE-2021-41098-1.patch new file mode 100644 index 0000000..e9fa4ef --- /dev/null +++ b/CVE-2021-41098-1.patch @@ -0,0 +1,684 @@ +From 412f4e3a396dd36677ca202df96aa36656f9c800 Mon Sep 17 00:00:00 2001 +From: Mike Dalessio +Date: Fri, 24 Sep 2021 14:13:39 -0400 +Subject: [PATCH] refactor(jruby): handle errors more consistently + +NokogiriErrorHandler stores RubyException but also accepts (and +type-converts) Exception and RaiseException. + +NokgiriHandler uses NokogiriErrorHandler under the hood. + +NokogiriErrorHandler classes use addError consistently everywhere. +--- + ext/java/nokogiri/XmlSaxParserContext.java | 106 +++++------------- + ext/java/nokogiri/XmlSaxPushParser.java | 42 +++---- + .../internals/NokogiriEntityResolver.java | 2 +- + .../internals/NokogiriErrorHandler.java | 37 ++++-- + .../nokogiri/internals/NokogiriHandler.java | 26 +---- + .../NokogiriNonStrictErrorHandler.java | 17 +-- + ...okogiriNonStrictErrorHandler4NekoHtml.java | 18 +-- + .../internals/NokogiriStrictErrorHandler.java | 13 ++- + .../internals/XmlDomParserContext.java | 27 ++--- + 9 files changed, 115 insertions(+), 173 deletions(-) + +diff --git a/ext/java/nokogiri/XmlSaxParserContext.java b/ext/java/nokogiri/XmlSaxParserContext.java +index 5537619..5727a10 100644 +--- a/ext/java/nokogiri/XmlSaxParserContext.java ++++ b/ext/java/nokogiri/XmlSaxParserContext.java +@@ -32,33 +32,23 @@ + + package nokogiri; + +-import static org.jruby.runtime.Helpers.invoke; +- + import java.io.IOException; + import java.io.InputStream; + +-import nokogiri.internals.NokogiriHandler; +-import nokogiri.internals.NokogiriHelpers; +-import nokogiri.internals.ParserContext; +-import nokogiri.internals.XmlSaxParser; ++import static org.jruby.runtime.Helpers.invoke; + ++import nokogiri.internals.*; + import org.apache.xerces.parsers.AbstractSAXParser; + import org.jruby.Ruby; + import org.jruby.RubyClass; + import org.jruby.RubyFixnum; +-import org.jruby.RubyModule; +-import org.jruby.RubyObjectAdapter; + import org.jruby.anno.JRubyClass; + import org.jruby.anno.JRubyMethod; + import org.jruby.exceptions.RaiseException; +-import org.jruby.javasupport.JavaEmbedUtils; ++import org.jruby.runtime.Helpers; + import org.jruby.runtime.ThreadContext; + import org.jruby.runtime.builtin.IRubyObject; +-import org.xml.sax.ContentHandler; +-import org.xml.sax.ErrorHandler; + import org.xml.sax.SAXException; +-import org.xml.sax.SAXNotRecognizedException; +-import org.xml.sax.SAXNotSupportedException; + import org.xml.sax.SAXParseException; + + /** +@@ -82,6 +72,7 @@ public class XmlSaxParserContext extends ParserContext { + protected AbstractSAXParser parser; + + protected NokogiriHandler handler; ++ protected NokogiriErrorHandler errorHandler; + private boolean replaceEntities = true; + private boolean recovery = false; + +@@ -179,24 +170,11 @@ public class XmlSaxParserContext extends ParserContext { + return (XmlSaxParserContext) NokogiriService.XML_SAXPARSER_CONTEXT_ALLOCATOR.allocate(runtime, klazz); + } + +- /** +- * Set a property of the underlying parser. +- */ +- protected void setProperty(String key, Object val) +- throws SAXNotRecognizedException, SAXNotSupportedException { +- parser.setProperty(key, val); +- } +- +- protected void setContentHandler(ContentHandler handler) { +- parser.setContentHandler(handler); +- } +- +- protected void setErrorHandler(ErrorHandler handler) { +- parser.setErrorHandler(handler); +- } +- + public final NokogiriHandler getNokogiriHandler() { return handler; } + ++ public final NokogiriErrorHandler ++ getNokogiriErrorHandler() { return errorHandler; } ++ + /** + * Perform any initialization prior to parsing with the handler + * handlerRuby. Convenience hook for subclasses. +@@ -221,6 +199,17 @@ public class XmlSaxParserContext extends ParserContext { + parser.parse(getInputSource()); + } + ++ protected static Options ++ defaultParseOptions(ThreadContext context) ++ { ++ return new ParserContext.Options( ++ RubyFixnum.fix2long(Helpers.invoke(context, ++ ((RubyClass)context.getRuntime().getClassFromPath("Nokogiri::XML::ParseOptions")) ++ .getConstant("DEFAULT_XML"), ++ "to_i")) ++ ); ++ } ++ + @JRubyMethod + public IRubyObject parse_with(ThreadContext context, IRubyObject handlerRuby) { + final Ruby runtime = context.getRuntime(); +@@ -229,14 +218,18 @@ public class XmlSaxParserContext extends ParserContext { + throw runtime.newArgumentError("argument must respond_to document"); + } + +- NokogiriHandler handler = this.handler = new NokogiriHandler(runtime, handlerRuby); +- preParse(runtime, handlerRuby, handler); ++ /* TODO: how should we pass in parse options? */ ++ ParserContext.Options options = defaultParseOptions(context); ++ ++ errorHandler = new NokogiriStrictErrorHandler(runtime, options.noError, options.noWarning); ++ handler = new NokogiriHandler(runtime, handlerRuby, errorHandler); + +- setContentHandler(handler); +- setErrorHandler(handler); ++ preParse(runtime, handlerRuby, handler); ++ parser.setContentHandler(handler); ++ parser.setErrorHandler(handler); + + try{ +- setProperty("http://xml.org/sax/properties/lexical-handler", handler); ++ parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); + } + catch (Exception ex) { + throw runtime.newRuntimeError("Problem while creating XML SAX Parser: " + ex.toString()); +@@ -269,8 +262,6 @@ public class XmlSaxParserContext extends ParserContext { + + postParse(runtime, handlerRuby, handler); + +- //maybeTrimLeadingAndTrailingWhitespace(context, handlerRuby); +- + return runtime.getNil(); + } + +@@ -310,48 +301,6 @@ public class XmlSaxParserContext extends ParserContext { + return context.runtime.newBoolean(recovery); + } + +- /** +- * If the handler's document is a FragmentHandler, attempt to trim +- * leading and trailing whitespace. +- * +- * This is a bit hackish and depends heavily on the internals of +- * FragmentHandler. +- */ +- protected void maybeTrimLeadingAndTrailingWhitespace(ThreadContext context, IRubyObject parser) { +- RubyObjectAdapter adapter = JavaEmbedUtils.newObjectAdapter(); +- RubyModule mod = context.getRuntime().getClassFromPath("Nokogiri::XML::FragmentHandler"); +- +- IRubyObject handler = adapter.getInstanceVariable(parser, "@document"); +- if (handler == null || handler.isNil() || !adapter.isKindOf(handler, mod)) +- return; +- IRubyObject stack = adapter.getInstanceVariable(handler, "@stack"); +- if (stack == null || stack.isNil()) +- return; +- // doc is finally a DocumentFragment whose nodes we can check +- IRubyObject doc = adapter.callMethod(stack, "first"); +- if (doc == null || doc.isNil()) +- return; +- +- IRubyObject children; +- +- for (;;) { +- children = adapter.callMethod(doc, "children"); +- IRubyObject first = adapter.callMethod(children, "first"); +- if (NokogiriHelpers.isBlank(first)) adapter.callMethod(first, "unlink"); +- else break; +- } +- +- for (;;) { +- children = adapter.callMethod(doc, "children"); +- IRubyObject last = adapter.callMethod(children, "last"); +- if (NokogiriHelpers.isBlank(last)) adapter.callMethod(last, "unlink"); +- else break; +- } +- +- // While we have a document, normalize it. +- ((XmlNode) doc).normalize(); +- } +- + @JRubyMethod(name="column") + public IRubyObject column(ThreadContext context) { + final Integer number = handler.getColumn(); +@@ -365,5 +314,4 @@ public class XmlSaxParserContext extends ParserContext { + if (number == null) return context.getRuntime().getNil(); + return RubyFixnum.newFixnum(context.getRuntime(), number.longValue()); + } +- + } +diff --git a/ext/java/nokogiri/XmlSaxPushParser.java b/ext/java/nokogiri/XmlSaxPushParser.java +index 8e65b92..b1b65a9 100644 +--- a/ext/java/nokogiri/XmlSaxPushParser.java ++++ b/ext/java/nokogiri/XmlSaxPushParser.java +@@ -32,21 +32,10 @@ + + package nokogiri; + +-import static nokogiri.internals.NokogiriHelpers.getNokogiriClass; +-import static org.jruby.runtime.Helpers.invoke; +- +-import java.io.ByteArrayInputStream; +-import java.io.IOException; +-import java.io.InputStream; +-import java.util.concurrent.ExecutionException; +-import java.util.concurrent.ExecutorService; +-import java.util.concurrent.Executors; +-import java.util.concurrent.Future; +-import java.util.concurrent.FutureTask; +-import java.util.concurrent.ThreadFactory; +- ++import nokogiri.internals.*; + import org.jruby.Ruby; + import org.jruby.RubyClass; ++import org.jruby.RubyException; + import org.jruby.RubyObject; + import org.jruby.anno.JRubyClass; + import org.jruby.anno.JRubyMethod; +@@ -54,11 +43,14 @@ import org.jruby.exceptions.RaiseException; + import org.jruby.runtime.ThreadContext; + import org.jruby.runtime.builtin.IRubyObject; + +-import nokogiri.internals.ClosedStreamException; +-import nokogiri.internals.NokogiriBlockingQueueInputStream; +-import nokogiri.internals.NokogiriHandler; +-import nokogiri.internals.NokogiriHelpers; +-import nokogiri.internals.ParserContext; ++import java.io.ByteArrayInputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.util.List; ++import java.util.concurrent.*; ++ ++import static nokogiri.internals.NokogiriHelpers.getNokogiriClass; ++import static org.jruby.runtime.Helpers.invoke; + + /** + * Class for Nokogiri::XML::SAX::PushParser +@@ -173,7 +165,8 @@ public class XmlSaxPushParser extends RubyObject { + + if (!options.recover && parserTask.getErrorCount() > errorCount0) { + terminateTask(context.runtime); +- throw ex = parserTask.getLastError(); ++ ex = parserTask.getLastError().toThrowable(); ++ throw ex; + } + + return this; +@@ -273,14 +266,13 @@ public class XmlSaxPushParser extends RubyObject { + + synchronized final int getErrorCount() { + // check for null because thread may not have started yet +- if (parser.getNokogiriHandler() == null) return 0; +- return parser.getNokogiriHandler().getErrorCount(); ++ if (parser.getNokogiriErrorHandler() == null) { return 0; } ++ return parser.getNokogiriErrorHandler().getErrors().size(); + } + +- synchronized final RaiseException getLastError() { +- return parser.getNokogiriHandler().getLastError(); ++ synchronized final RubyException getLastError() { ++ List errors = parser.getNokogiriErrorHandler().getErrors(); ++ return errors.get(errors.size() - 1); + } +- + } +- + } +diff --git a/ext/java/nokogiri/internals/NokogiriEntityResolver.java b/ext/java/nokogiri/internals/NokogiriEntityResolver.java +index d97da66..48942d0 100644 +--- a/ext/java/nokogiri/internals/NokogiriEntityResolver.java ++++ b/ext/java/nokogiri/internals/NokogiriEntityResolver.java +@@ -68,7 +68,7 @@ public class NokogiriEntityResolver implements EntityResolver2 { + } + + private void addError(String errorMessage) { +- if (handler != null) handler.errors.add(new Exception(errorMessage)); ++ if (handler != null) { handler.addError(new Exception(errorMessage)); } + } + + /** +diff --git a/ext/java/nokogiri/internals/NokogiriErrorHandler.java b/ext/java/nokogiri/internals/NokogiriErrorHandler.java +index 7980107..13b1725 100644 +--- a/ext/java/nokogiri/internals/NokogiriErrorHandler.java ++++ b/ext/java/nokogiri/internals/NokogiriErrorHandler.java +@@ -32,12 +32,16 @@ + + package nokogiri.internals; + +-import java.util.ArrayList; +-import java.util.List; +- ++import nokogiri.XmlSyntaxError; + import org.apache.xerces.xni.parser.XMLErrorHandler; ++import org.jruby.Ruby; ++import org.jruby.RubyException; ++import org.jruby.exceptions.RaiseException; + import org.xml.sax.ErrorHandler; + ++import java.util.ArrayList; ++import java.util.List; ++ + /** + * Super class of error handlers. + * +@@ -48,19 +52,36 @@ import org.xml.sax.ErrorHandler; + * @author Yoko Harada + */ + public abstract class NokogiriErrorHandler implements ErrorHandler, XMLErrorHandler { +- protected final List errors; ++ private final Ruby runtime; ++ protected final List errors; + protected boolean noerror; + protected boolean nowarning; + +- public NokogiriErrorHandler(boolean noerror, boolean nowarning) { +- this.errors = new ArrayList(4); ++ public NokogiriErrorHandler(Ruby runtime, boolean noerror, boolean nowarning) ++ this.runtime = runtime; ++ this.errors = new ArrayList(4); + this.noerror = noerror; + this.nowarning = nowarning; + } + +- List getErrors() { return errors; } ++ public List getErrors() { return errors; } + +- public void addError(Exception ex) { errors.add(ex); } ++ public void addError(Exception ex) ++ { ++ addError(XmlSyntaxError.createXMLSyntaxError(runtime, ex)); ++ } ++ ++ public void ++ addError(RubyException ex) ++ { ++ errors.add(ex); ++ } ++ ++ public void ++ addError(RaiseException ex) ++ { ++ addError(ex.getException()); ++ } + + protected boolean usesNekoHtml(String domain) { + return "http://cyberneko.org/html".equals(domain); +diff --git a/ext/java/nokogiri/internals/NokogiriHandler.java b/ext/java/nokogiri/internals/NokogiriHandler.java +index 5e34be1..2da4011 100644 +--- a/ext/java/nokogiri/internals/NokogiriHandler.java ++++ b/ext/java/nokogiri/internals/NokogiriHandler.java +@@ -69,23 +69,17 @@ public class NokogiriHandler extends DefaultHandler2 implements XmlDeclHandler { + private final Ruby runtime; + private final RubyClass attrClass; + private final IRubyObject object; +- +- /** +- * Stores parse errors with the most-recent error last. +- * +- * TODO: should these be stored in the document 'errors' array? +- * Currently only string messages are stored there. +- */ +- private final LinkedList errors = new LinkedList(); ++ private NokogiriErrorHandler errorHandler; + + private Locator locator; + private boolean needEmptyAttrCheck; + +- public NokogiriHandler(Ruby runtime, IRubyObject object) { ++ public NokogiriHandler(Ruby runtime, IRubyObject object, NokogiriErrorHandler errorHandler) { + assert object != null; + this.runtime = runtime; + this.attrClass = (RubyClass) runtime.getClassFromPath("Nokogiri::XML::SAX::Parser::Attribute"); + this.object = object; ++ this.errorHandler = errorHandler; + charactersBuilder = new StringBuilder(); + String objectName = object.getMetaClass().getName(); + if ("Nokogiri::HTML::SAX::Parser".equals(objectName)) needEmptyAttrCheck = true; +@@ -249,9 +243,9 @@ public class NokogiriHandler extends DefaultHandler2 implements XmlDeclHandler { + try { + final String msg = ex.getMessage(); + call("error", runtime.newString(msg == null ? "" : msg)); +- addError(new RaiseException(XmlSyntaxError.createError(runtime, ex), true)); ++ errorHandler.addError(ex); + } catch( RaiseException e) { +- addError(e); ++ errorHandler.addError(e); + throw e; + } + } +@@ -272,16 +266,8 @@ public class NokogiriHandler extends DefaultHandler2 implements XmlDeclHandler { + call("warning", runtime.newString(msg == null ? "" : msg)); + } + +- protected synchronized void addError(RaiseException e) { +- errors.add(e); +- } +- + public synchronized int getErrorCount() { +- return errors.size(); +- } +- +- public synchronized RaiseException getLastError() { +- return errors.getLast(); ++ return errorHandler.getErrors().size(); + } + + private void call(String methodName) { +diff --git a/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java b/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java +index 15b622c..f49e13d 100644 +--- a/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java ++++ b/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler.java +@@ -33,6 +33,7 @@ + package nokogiri.internals; + + import org.apache.xerces.xni.parser.XMLParseException; ++import org.jruby.Ruby; + import org.xml.sax.SAXException; + import org.xml.sax.SAXParseException; + +@@ -43,16 +44,16 @@ import org.xml.sax.SAXParseException; + * @author Yoko Harada + */ + public class NokogiriNonStrictErrorHandler extends NokogiriErrorHandler{ +- public NokogiriNonStrictErrorHandler(boolean noerror, boolean nowarning) { +- super(noerror, nowarning); ++ public NokogiriNonStrictErrorHandler(Ruby runtime, boolean noerror, boolean nowarning) { ++ super(runtime, noerror, nowarning); + } + + public void warning(SAXParseException ex) throws SAXException { +- errors.add(ex); ++ addError(ex); + } + + public void error(SAXParseException ex) throws SAXException { +- errors.add(ex); ++ addError(ex); + } + + public void fatalError(SAXParseException ex) throws SAXException { +@@ -61,7 +62,7 @@ public class NokogiriNonStrictErrorHandler extends NokogiriErrorHandler{ + // found in the prolog, instead it will keep calling this method and we'll + // keep inserting the error in the document errors array until we run + // out of memory +- errors.add(ex); ++ addError(ex); + String message = ex.getMessage(); + + // The problem with Xerces is that some errors will cause the +@@ -74,15 +75,15 @@ public class NokogiriNonStrictErrorHandler extends NokogiriErrorHandler{ + } + + public void error(String domain, String key, XMLParseException e) { +- errors.add(e); ++ addError(e); + } + + public void fatalError(String domain, String key, XMLParseException e) { +- errors.add(e); ++ addError(e); + } + + public void warning(String domain, String key, XMLParseException e) { +- errors.add(e); ++ addError(e); + } + + /* +diff --git a/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java b/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +index 011af24..a2c6b33 100644 +--- a/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java ++++ b/ext/java/nokogiri/internals/NokogiriNonStrictErrorHandler4NekoHtml.java +@@ -33,6 +33,7 @@ + package nokogiri.internals; + + import org.apache.xerces.xni.parser.XMLParseException; ++import org.jruby.Ruby; + import org.xml.sax.SAXException; + import org.xml.sax.SAXParseException; + +@@ -50,12 +51,13 @@ import org.xml.sax.SAXParseException; + */ + public class NokogiriNonStrictErrorHandler4NekoHtml extends NokogiriErrorHandler { + +- public NokogiriNonStrictErrorHandler4NekoHtml(boolean nowarning) { +- super(false, nowarning); ++ public NokogiriNonStrictErrorHandler4NekoHtml(Ruby runtime, boolean nowarning) { ++ super(runtime, false, nowarning); + } + + public NokogiriNonStrictErrorHandler4NekoHtml(boolean noerror, boolean nowarning) { +- super(noerror, nowarning); ++ public NokogiriNonStrictErrorHandler4NekoHtml(Ruby runtime, boolean noerror, boolean nowarning) { ++ super(runtime, noerror, nowarning); + } + + public void warning(SAXParseException ex) throws SAXException { +@@ -63,11 +65,11 @@ public class NokogiriNonStrictErrorHandler4NekoHtml extends NokogiriErrorHandler + } + + public void error(SAXParseException ex) throws SAXException { +- errors.add(ex); ++ addError(ex); + } + + public void fatalError(SAXParseException ex) throws SAXException { +- errors.add(ex); ++ addError(ex); + } + + /** +@@ -83,7 +85,7 @@ public class NokogiriNonStrictErrorHandler4NekoHtml extends NokogiriErrorHandler + * @param e Exception. + */ + public void error(String domain, String key, XMLParseException e) { +- errors.add(e); ++ addError(e); + } + + /** +@@ -99,7 +101,7 @@ public class NokogiriNonStrictErrorHandler4NekoHtml extends NokogiriErrorHandler + * @param e Exception. + */ + public void fatalError(String domain, String key, XMLParseException e) { +- errors.add(e); ++ addError(e); + } + + /** +@@ -115,7 +117,7 @@ public class NokogiriNonStrictErrorHandler4NekoHtml extends NokogiriErrorHandler + * @param e Exception. + */ + public void warning(String domain, String key, XMLParseException e) { +- errors.add(e); ++ addError(e); + } + + } +diff --git a/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java b/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +index 10315fa..fbf9787 100644 +--- a/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java ++++ b/ext/java/nokogiri/internals/NokogiriStrictErrorHandler.java +@@ -33,6 +33,7 @@ + package nokogiri.internals; + + import org.apache.xerces.xni.parser.XMLParseException; ++import org.jruby.Ruby; + import org.xml.sax.SAXException; + import org.xml.sax.SAXParseException; + +@@ -44,18 +45,18 @@ import org.xml.sax.SAXParseException; + * @author Yoko Harada + */ + public class NokogiriStrictErrorHandler extends NokogiriErrorHandler { +- public NokogiriStrictErrorHandler(boolean noerror, boolean nowarning) { +- super(noerror, nowarning); ++ public NokogiriStrictErrorHandler(Ruby runtime, boolean noerror, boolean nowarning) { ++ super(runtime, noerror, nowarning); + } + + public void warning(SAXParseException spex) throws SAXException { + if (!nowarning) throw spex; +- else errors.add(spex); ++ else { addError(spex); } + } + + public void error(SAXParseException spex) throws SAXException { + if (!noerror) throw spex; +- else errors.add(spex); ++ else { addError(spex); } + } + + public void fatalError(SAXParseException spex) throws SAXException { +@@ -64,7 +65,7 @@ public class NokogiriStrictErrorHandler extends NokogiriErrorHandler { + + public void error(String domain, String key, XMLParseException e) throws XMLParseException { + if (!noerror) throw e; +- else errors.add(e); ++ else { addError(e); } + } + + public void fatalError(String domain, String key, XMLParseException e) throws XMLParseException { +@@ -73,6 +74,6 @@ public class NokogiriStrictErrorHandler extends NokogiriErrorHandler { + + public void warning(String domain, String key, XMLParseException e) throws XMLParseException { + if (!nowarning) throw e; +- if (!usesNekoHtml(domain)) errors.add(e); ++ if (!usesNekoHtml(domain)) { addError(e); } + } + } +diff --git a/ext/java/nokogiri/internals/XmlDomParserContext.java b/ext/java/nokogiri/internals/XmlDomParserContext.java +index 89af2bc..839399b 100644 +--- a/ext/java/nokogiri/internals/XmlDomParserContext.java ++++ b/ext/java/nokogiri/internals/XmlDomParserContext.java +@@ -32,23 +32,17 @@ + + package nokogiri.internals; + +-import static nokogiri.internals.NokogiriHelpers.getNokogiriClass; +-import static nokogiri.internals.NokogiriHelpers.isBlank; +- + import java.io.IOException; + import java.util.ArrayList; + import java.util.List; + +-import nokogiri.NokogiriService; ++import static nokogiri.internals.NokogiriHelpers.isBlank; ++ + import nokogiri.XmlDocument; + import nokogiri.XmlDtd; + import nokogiri.XmlSyntaxError; +- + import org.apache.xerces.parsers.DOMParser; +-import org.jruby.Ruby; +-import org.jruby.RubyArray; +-import org.jruby.RubyClass; +-import org.jruby.RubyFixnum; ++import org.jruby.*; + import org.jruby.exceptions.RaiseException; + import org.jruby.runtime.ThreadContext; + import org.jruby.runtime.builtin.IRubyObject; +@@ -78,7 +72,6 @@ public class XmlDomParserContext extends ParserContext { + protected static final String FEATURE_NOT_EXPAND_ENTITY = + "http://apache.org/xml/features/dom/create-entity-ref-nodes"; + protected static final String FEATURE_VALIDATION = "http://xml.org/sax/features/validation"; +- private static final String XINCLUDE_FEATURE_ID = "http://apache.org/xml/features/xinclude"; + private static final String SECURITY_MANAGER = "http://apache.org/xml/properties/security-manager"; + + protected ParserContext.Options options; +@@ -96,15 +89,15 @@ public class XmlDomParserContext extends ParserContext { + this.options = new ParserContext.Options(RubyFixnum.fix2long(options)); + java_encoding = NokogiriHelpers.getValidEncoding(runtime, encoding); + ruby_encoding = encoding; +- initErrorHandler(); ++ initErrorHandler(runtime); + initParser(runtime); + } + +- protected void initErrorHandler() { ++ protected void initErrorHandler(Ruby runtime) { + if (options.recover) { +- errorHandler = new NokogiriNonStrictErrorHandler(options.noError, options.noWarning); ++ errorHandler = new NokogiriNonStrictErrorHandler(runtime, options.noError, options.noWarning); + } else { +- errorHandler = new NokogiriStrictErrorHandler(options.noError, options.noWarning); ++ errorHandler = new NokogiriStrictErrorHandler(runtime, options.noError, options.noWarning); + } + } + +@@ -176,12 +169,10 @@ public class XmlDomParserContext extends ParserContext { + + public static RubyArray mapErrors(ThreadContext context, NokogiriErrorHandler errorHandler) { + final Ruby runtime = context.runtime; +- final List errors = errorHandler.getErrors(); ++ final List errors = errorHandler.getErrors(); + final IRubyObject[] errorsAry = new IRubyObject[errors.size()]; + for (int i = 0; i < errors.size(); i++) { +- XmlSyntaxError xmlSyntaxError = XmlSyntaxError.createXMLSyntaxError(runtime); +- xmlSyntaxError.setException(errors.get(i)); +- errorsAry[i] = xmlSyntaxError; ++ errorsAry[i] = errors.get(i); + } + return runtime.newArrayNoCopy(errorsAry); + } +-- +2.27.0 + diff --git a/CVE-2021-41098-2.patch b/CVE-2021-41098-2.patch new file mode 100644 index 0000000..9a582e8 --- /dev/null +++ b/CVE-2021-41098-2.patch @@ -0,0 +1,28 @@ +From 382860304b2efbf837cb3fcbbe806c81c27bf6b1 Mon Sep 17 00:00:00 2001 +From: Mike Dalessio +Date: Fri, 24 Sep 2021 14:15:26 -0400 +Subject: [PATCH] fix(jruby): SAX parser uses an entity resolver + +to avoid XXE injections. + +This behavior now matches the CRuby implementation. +--- + ext/java/nokogiri/XmlSaxParserContext.java | 1 + + test/xml/sax/test_parser.rb | 33 ++++++++++++++++++++++ + 2 files changed, 34 insertions(+) + +diff --git a/ext/java/nokogiri/XmlSaxParserContext.java b/ext/java/nokogiri/XmlSaxParserContext.java +index 5727a10..e614ce9 100644 +--- a/ext/java/nokogiri/XmlSaxParserContext.java ++++ b/ext/java/nokogiri/XmlSaxParserContext.java +@@ -227,6 +227,7 @@ public class XmlSaxParserContext extends ParserContext { + preParse(runtime, handlerRuby, handler); + parser.setContentHandler(handler); + parser.setErrorHandler(handler); ++ parser.setEntityResolver(new NokogiriEntityResolver(runtime, errorHandler, options)); + + try{ + parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler); +-- +2.27.0 + diff --git a/rubygem-nokogiri.spec b/rubygem-nokogiri.spec index 2515526..7b9cf77 100644 --- a/rubygem-nokogiri.spec +++ b/rubygem-nokogiri.spec @@ -7,7 +7,7 @@ Summary: An HTML, XML, SAX, and Reader parser Name: rubygem-%{gem_name} Version: %{mainver} -Release: 2 +Release: 3 License: MIT URL: https://nokogiri.org Source0: https://rubygems.org/gems/%{gem_name}-%{mainver}%{?prever}.gem @@ -16,6 +16,8 @@ Source1: https://github.com/sparklemotion/%{gem_name}/archive/v%{mainver} Patch0: %{name}-1.6.6.4-shutdown-libxml2-warning.patch Patch1: CVE-2020-26247-pre.patch Patch2: CVE-2020-26247.patch +Patch3: CVE-2021-41098-1.patch +Patch4: CVE-2021-41098-2.patch BuildRequires: ruby(release) ruby(rubygems) rubygem(minitest) rubygems-devel Obsoletes: ruby-%{gem_name} <= 1.5.2-2 BuildRequires: gcc rubygem(pkg-config) libxml2-devel libxslt-devel ruby-devel @@ -57,6 +59,13 @@ cd %{gem_name}-%{version} %patch0 -p1 %patch1 -p1 %patch2 -p1 + +#The file exists only in the source code directory,not in the GEM. +cd $TOPDIR/%{gem_name}-%{version} +%patch3 -p1 +%patch4 -p1 +cd - + gem specification -l --ruby %{SOURCE0} > %{gem_name}.gemspec sed -i \ -e 's|, "ports/archives/[^"][^"]*"||g' \ @@ -149,6 +158,9 @@ popd %{gem_dir}/doc/%{gem_name}-%{mainver}%{?prever}/ %changelog +* Tue Oct 12 2021 yaoxin - 1.10.5-3 +- fix CVE-2021-41098 + * Wed Mar 17 2021 zhanghua - 1.10.5-2 - fix CVE-2020-26247 -- Gitee