diff --git a/rubygem-nokogiri-1.13.3-CVE-2022-24836.patch b/rubygem-nokogiri-1.13.3-CVE-2022-24836.patch new file mode 100644 index 0000000..ea6b775 --- /dev/null +++ b/rubygem-nokogiri-1.13.3-CVE-2022-24836.patch @@ -0,0 +1,42 @@ +commit e444525ef1634b675cd1cf52d39f4320ef0aecfd +Author: Mike Dalessio +Date: Sun Apr 10 14:42:04 2022 -0400 + + fix(perf): HTML4::EncodingReader detection + +diff --git a/lib/nokogiri/html4/document.rb b/lib/nokogiri/html4/document.rb +index 177efc04..fbc22d20 100644 +--- a/lib/nokogiri/html4/document.rb ++++ b/lib/nokogiri/html4/document.rb +@@ -268,7 +268,7 @@ module Nokogiri + end + + def self.detect_encoding(chunk) +- (m = chunk.match(/\A(<\?xml[ \t\r\n]+[^>]*>)/)) && ++ (m = chunk.match(/\A(<\?xml[ \t\r\n][^>]*>)/)) && + (return Nokogiri.XML(m[1]).encoding) + + if Nokogiri.jruby? +diff --git a/test/html4/test_document_encoding.rb b/test/html4/test_document_encoding.rb +index 61153017..ecb4aa9a 100644 +--- a/test/html4/test_document_encoding.rb ++++ b/test/html4/test_document_encoding.rb +@@ -155,6 +155,18 @@ class TestNokogiriHtmlDocument < Nokogiri::TestCase + end + end + end ++ ++ it "does not start backtracking during detection of XHTML encoding" do ++ # this test is a quick and dirty version ++ # of the more complete perf test that is on main. ++ n = 40_000 ++ redos_string = " +Date: Fri, 6 May 2022 21:57:41 -0400 +Subject: [PATCH] fix: {HTML4,XML}::SAX::{Parser,ParserContext} check arg types + +Previously, arguments of the wrong type might cause segfault on CRuby. +--- + CHANGELOG.md | 3 ++- + ext/java/nokogiri/Html4SaxParserContext.java | 11 +++++++++++ + ext/java/nokogiri/XmlSaxParserContext.java | 7 +++++-- + ext/java/nokogiri/internals/ParserContext.java | 8 +++++++- + ext/nokogiri/html4_sax_parser_context.c | 5 ++--- + ext/nokogiri/xml_sax_parser_context.c | 13 ++++++++++--- + lib/nokogiri/html4/sax/parser.rb | 2 +- + test/html4/sax/test_parser.rb | 8 +++++++- + test/html4/sax/test_parser_context.rb | 9 +++++++++ + test/xml/sax/test_parser.rb | 8 +++++++- + test/xml/sax/test_parser_context.rb | 7 +++++++ + 11 files changed, 68 insertions(+), 13 deletions(-) + +diff --git a/ext/nokogiri/html4_sax_parser_context.c b/ext/nokogiri/html4_sax_parser_context.c +index dec0d88fe..54adca4cb 100644 +--- a/ext/nokogiri/html4_sax_parser_context.c ++++ b/ext/nokogiri/html4_sax_parser_context.c +@@ -19,9 +19,8 @@ parse_memory(VALUE klass, VALUE data, VALUE encoding) + { + htmlParserCtxtPtr ctxt; + +- if (NIL_P(data)) { +- rb_raise(rb_eArgError, "data cannot be nil"); +- } ++ Check_Type(data, T_STRING); ++ + if (!(int)RSTRING_LEN(data)) { + rb_raise(rb_eRuntimeError, "data cannot be empty"); + } +diff --git a/ext/nokogiri/xml_sax_parser_context.c b/ext/nokogiri/xml_sax_parser_context.c +index 60449347a..60c491984 100644 +--- a/ext/nokogiri/xml_sax_parser_context.c ++++ b/ext/nokogiri/xml_sax_parser_context.c +@@ -2,6 +2,8 @@ + + VALUE cNokogiriXmlSaxParserContext ; + ++static ID id_read; ++ + static void + deallocate(xmlParserCtxtPtr ctxt) + { +@@ -26,6 +28,10 @@ parse_io(VALUE klass, VALUE io, VALUE encoding) + xmlParserCtxtPtr ctxt; + xmlCharEncoding enc = (xmlCharEncoding)NUM2INT(encoding); + ++ if (!rb_respond_to(io, id_read)) { ++ rb_raise(rb_eTypeError, "argument expected to respond to :read"); ++ } ++ + ctxt = xmlCreateIOParserCtxt(NULL, NULL, + (xmlInputReadCallback)noko_io_read, + (xmlInputCloseCallback)noko_io_close, +@@ -62,9 +68,8 @@ parse_memory(VALUE klass, VALUE data) + { + xmlParserCtxtPtr ctxt; + +- if (NIL_P(data)) { +- rb_raise(rb_eArgError, "data cannot be nil"); +- } ++ Check_Type(data, T_STRING); ++ + if (!(int)RSTRING_LEN(data)) { + rb_raise(rb_eRuntimeError, "data cannot be empty"); + } +@@ -278,4 +283,6 @@ noko_init_xml_sax_parser_context() + rb_define_method(cNokogiriXmlSaxParserContext, "recovery", get_recovery, 0); + rb_define_method(cNokogiriXmlSaxParserContext, "line", line, 0); + rb_define_method(cNokogiriXmlSaxParserContext, "column", column, 0); ++ ++ id_read = rb_intern("read"); + } +diff --git a/lib/nokogiri/html4/sax/parser.rb b/lib/nokogiri/html4/sax/parser.rb +index 2a074b6b9..1f8c03af6 100644 +--- a/lib/nokogiri/html4/sax/parser.rb ++++ b/lib/nokogiri/html4/sax/parser.rb +@@ -28,7 +28,7 @@ class Parser < Nokogiri::XML::SAX::Parser + ### + # Parse html stored in +data+ using +encoding+ + def parse_memory(data, encoding = "UTF-8") +- raise ArgumentError unless data ++ raise TypeError unless String === data + return if data.empty? + ctx = ParserContext.memory(data, encoding) + yield ctx if block_given? +diff --git a/test/html4/sax/test_parser.rb b/test/html4/sax/test_parser.rb +index 3917dce2e..4dc6ac61f 100644 +--- a/test/html4/sax/test_parser.rb ++++ b/test/html4/sax/test_parser.rb +@@ -54,7 +54,7 @@ def test_parse_file_with_dir + end + + def test_parse_memory_nil +- assert_raises(ArgumentError) do ++ assert_raises(TypeError) do + @parser.parse_memory(nil) + end + end +@@ -161,6 +161,12 @@ def test_parsing_dom_error_from_io + def test_empty_processing_instruction + @parser.parse_memory("this will segfault") + end ++ ++ it "handles invalid types gracefully" do ++ assert_raises(TypeError) { Nokogiri::HTML::SAX::Parser.new.parse(0xcafecafe) } ++ assert_raises(TypeError) { Nokogiri::HTML::SAX::Parser.new.parse_memory(0xcafecafe) } ++ assert_raises(TypeError) { Nokogiri::HTML::SAX::Parser.new.parse_io(0xcafecafe) } ++ end + end + end + end +diff --git a/test/html4/sax/test_parser_context.rb b/test/html4/sax/test_parser_context.rb +index 0a0eda64c..594a3ac82 100644 +--- a/test/html4/sax/test_parser_context.rb ++++ b/test/html4/sax/test_parser_context.rb +@@ -40,6 +40,15 @@ def test_from_file + ctx.parse_with(parser) + # end + end ++ ++ def test_graceful_handling_of_invalid_types ++ assert_raises(TypeError) { ParserContext.new(0xcafecafe) } ++ assert_raises(TypeError) { ParserContext.memory(0xcafecafe, "UTF-8") } ++ assert_raises(TypeError) { ParserContext.io(0xcafecafe, 1) } ++ assert_raises(TypeError) { ParserContext.io(StringIO.new("asdf"), "should be an index into ENCODINGS") } ++ assert_raises(TypeError) { ParserContext.file(0xcafecafe, "UTF-8") } ++ assert_raises(TypeError) { ParserContext.file("path/to/file", 0xcafecafe) } ++ end + end + end + end +diff --git a/test/xml/sax/test_parser.rb b/test/xml/sax/test_parser.rb +index 6c0f1fc88..ac7d4ead0 100644 +--- a/test/xml/sax/test_parser.rb ++++ b/test/xml/sax/test_parser.rb +@@ -73,6 +73,12 @@ class TestCase + end + end + ++ it "handles invalid types gracefully" do ++ assert_raises(TypeError) { Nokogiri::XML::SAX::Parser.new.parse(0xcafecafe) } ++ assert_raises(TypeError) { Nokogiri::XML::SAX::Parser.new.parse_memory(0xcafecafe) } ++ assert_raises(TypeError) { Nokogiri::XML::SAX::Parser.new.parse_io(0xcafecafe) } ++ end ++ + it :test_namespace_declaration_order_is_saved do + parser.parse(<<~EOF) + +@@ -263,7 +269,7 @@ def call_parse_io_with_encoding(encoding) + end + + it :test_render_parse_nil_param do +- assert_raises(ArgumentError) { parser.parse_memory(nil) } ++ assert_raises(TypeError) { parser.parse_memory(nil) } + end + + it :test_bad_encoding_args do +diff --git a/test/xml/sax/test_parser_context.rb b/test/xml/sax/test_parser_context.rb +index e38efd271..ba9857943 100644 +--- a/test/xml/sax/test_parser_context.rb ++++ b/test/xml/sax/test_parser_context.rb +@@ -80,6 +80,13 @@ def test_recovery + assert(pc.recovery) + end + ++ def test_graceful_handling_of_invalid_types ++ assert_raises(TypeError) { ParserContext.new(0xcafecafe) } ++ assert_raises(TypeError) { ParserContext.memory(0xcafecafe) } ++ assert_raises(TypeError) { ParserContext.io(0xcafecafe, 1) } ++ assert_raises(TypeError) { ParserContext.io(StringIO.new("asdf"), "should be an index into ENCODINGS") } ++ end ++ + def test_from_io + ctx = ParserContext.new(StringIO.new("fo"), "UTF-8") + assert(ctx) diff --git a/rubygem-nokogiri-1.13.x-testsuite-libxml2-2-9-14.patch b/rubygem-nokogiri-1.13.x-testsuite-libxml2-2-9-14.patch new file mode 100644 index 0000000..467186a --- /dev/null +++ b/rubygem-nokogiri-1.13.x-testsuite-libxml2-2-9-14.patch @@ -0,0 +1,63 @@ +From 520f4e7d64eab9b862b7fe9c683d348be9f4eb0a Mon Sep 17 00:00:00 2001 +From: Mike Dalessio +Date: Mon, 2 May 2022 18:04:39 -0400 +Subject: [PATCH] dep: update libxml2 to v2.9.14 + +from v2.9.13 + +https://gitlab.gnome.org/GNOME/libxml2/-/releases/v2.9.14 +--- + dependencies.yml | 6 +-- + ...t-approach-to-fix-quadratic-behavior.patch | 45 ------------------- + test/html4/test_comments.rb | 25 ++++++++++- + test/html4/test_document.rb | 25 +++++++---- + 4 files changed, 43 insertions(+), 58 deletions(-) + delete mode 100644 patches/libxml2/0010-Revert-Different-approach-to-fix-quadratic-behavior.patch + +diff --git a/test/html4/test_comments.rb b/test/html4/test_comments.rb +index 32d7a8785..56fd50682 100644 +--- a/test/html4/test_comments.rb ++++ b/test/html4/test_comments.rb +@@ -173,7 +173,7 @@ class TestComment < Nokogiri::TestCase + let(:body) { doc.at_css("body") } + let(:subject) { doc.at_css("div#under-test") } + +- if Nokogiri.uses_libxml? ++ if Nokogiri.uses_libxml?("<=2.9.13") + it "ignores up to the next '>'" do # NON-COMPLIANT + assert_equal 2, body.children.length + assert_equal body.children[0], subject +@@ -183,10 +183,33 @@ class TestComment < Nokogiri::TestCase + assert body.children[1].text? + assert_equal "-->hello", body.children[1].content + end ++ elsif Nokogiri.uses_libxml? ++ it "parses as pcdata" do # NON-COMPLIANT ++ assert_equal 1, body.children.length ++ assert_equal subject, body.children.first ++ ++ assert_equal 3, subject.children.length ++ subject.children[0].tap do |child| ++ assert_predicate(child, :text?) ++ assert_equal("hello", child.content) ++ end ++ end + end + + if Nokogiri.jruby? + it "ignores up to the next '-->'" do # NON-COMPLIANT ++ assert_equal 1, body.children.length ++ assert_equal subject, body.children.first ++ + assert_equal 1, subject.children.length + assert subject.children[0].text? + assert_equal "hello", subject.children[0].content diff --git a/rubygem-nokogiri.spec b/rubygem-nokogiri.spec index 7360559..70ffab1 100644 --- a/rubygem-nokogiri.spec +++ b/rubygem-nokogiri.spec @@ -1,7 +1,7 @@ %global mainver 1.13.1 #%%global prever .rc4 -%global mainrel 1 +%global mainrel 4 %global prerpmver %(echo "%{?prever}" | sed -e 's|\\.||g') %global gem_name nokogiri @@ -32,6 +32,15 @@ Source2: nokogiri-create-full-tarball.sh #Patch0: rubygem-nokogiri-1.5.0-allow-non-crosscompile.patch # Shut down libxml2 version unmatching warning Patch0: %{name}-1.11.0.rc4-shutdown-libxml2-warning.patch +# https://github.com/sparklemotion/nokogiri/commit/e444525ef1634b675cd1cf52d39f4320ef0aecfd +# Fix for CVE-2022-24836 +Patch1: %{name}-1.13.3-CVE-2022-24836.patch +# https://github.com/sparklemotion/nokogiri/commit/db05ba9a1bd4b90aa6c76742cf6102a7c7297267 +# Fix for CVE-2022-24836, backported +Patch2: %{name}-1.13.5-6-CVE-2022-29181-backport.patch +# Test suite for libxml2 2.9.14 +# https://github.com/sparklemotion/nokogiri/commit/520f4e7d64eab9b862b7fe9c683d348be9f4eb0a +Patch3: %{name}-1.13.x-testsuite-libxml2-2-9-14.patch BuildRequires: ruby(release) BuildRequires: ruby(rubygems) ## @@ -91,7 +100,15 @@ This package provides non-Gem support for %{gem_name}. mv ../%{gem_name}-%{version}.gemspec . # patches +( +cd %{gem_name}-%{version}/ %patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +cd .. +cp -a %{gem_name}-%{version}/{lib,ext} . +) # remove bundled external libraries sed -i \ @@ -222,6 +239,12 @@ sed -i test/helper.rb \ sed -i '/require..minitest.reporters./ s/^/#/' test/helper.rb sed -i '/Minitest::Reporters/ s/^/#/' test/helper.rb +# PPC64LE with ruby3.1 does not seem to support GC.compact +# (On Fedora, the above is backported to 3.0 branch) +%ifarch ppc64le +export NOKOGIRI_TEST_GC_LEVEL=major +%endif + # Need investigation. For now anyway build env \ RUBYLIB=".:lib:test:ext" \ @@ -260,6 +283,15 @@ popd %{gem_dir}/doc/%{gem_name}-%{mainver}%{?prever}/ %changelog +* Fri Jun 3 2022 Mamoru TASAKA - 1.13.1-4 +- Make test suite pass with libxml2 2.9.14 + +* Tue May 10 2022 Mamoru TASAKA - 1.13.1-3 +- Backport CVE-2022-29181 from between 1.13.5 and 1.13.6 + +* Thu Apr 14 2022 Mamoru TASAKA - 1.13.1-2 +- Backport CVE-2022-24836 from between 1.13.3 and 1.13.4 + * Fri Jan 14 2022 Mamoru TASAKA - 1.13.1-1 - 1.13.1