From ead83c6d23c77103756b10a0ec6501a8a5601c52 Mon Sep 17 00:00:00 2001 From: wszlight Date: Wed, 22 Feb 2023 12:29:15 +0000 Subject: [PATCH] fix CVE-2022-44566 fix CVE-2022-44566 CVE-2023-22794 --- CVE-2022-44566-pre0.patch | 45 +++++++++++++ CVE-2022-44566-pre1.patch | 25 ++++++++ CVE-2022-44566.patch | 132 ++++++++++++++++++++++++++++++++++++++ CVE-2023-22794.patch | 122 +++++++++++++++++++++++++++++++++++ rubygem-activerecord.spec | 18 +++++- 5 files changed, 339 insertions(+), 3 deletions(-) create mode 100644 CVE-2022-44566-pre0.patch create mode 100644 CVE-2022-44566-pre1.patch create mode 100644 CVE-2022-44566.patch create mode 100644 CVE-2023-22794.patch diff --git a/CVE-2022-44566-pre0.patch b/CVE-2022-44566-pre0.patch new file mode 100644 index 0000000..a116567 --- /dev/null +++ b/CVE-2022-44566-pre0.patch @@ -0,0 +1,45 @@ +From 8ce4bd1be83c08c30c34af4d0f1a726066128176 Mon Sep 17 00:00:00 2001 +From: Zack +Date: Fri, 22 Apr 2022 15:21:40 -0400 +Subject: [PATCH 1/1] Change ActiveRecord::Coders::YAMLColumn default to + safe_load + +In Psych >= 4.0.0, load defaults to safe_load. This commit +makes the ActiveRecord::Coders::YAMLColum class use Psych safe_load +as the Rails default. + +This default is configurable via ActiveRecord::Base.use_yaml_unsafe_load + +We conditionally fallback to the correct unsafe load if use_yaml_unsafe_load +is set to true. unsafe_load was introduced in Psych >= 4.0.0 + +The list of safe_load permitted classes is configurable via +ActiveRecord::Base.yaml_column_permitted_classes + +[CVE-2022-32224] +--- + activerecord/lib/active_record/core.rb | 8 ++ + 1 files changed, 337 insertions(+), 36 deletions(-) + +diff --git a/activerecord-6.1.4.1/lib/active_record/core.rb b/activerecord-6.1.4.1/lib/active_record/core.rb +index 3fb15f9531..379cae1830 100644 +--- a/activerecord-6.1.4.1/lib/active_record/core.rb ++++ b/activerecord-6.1.4.1/lib/active_record/core.rb +@@ -155,6 +155,14 @@ def self.configurations + + mattr_accessor :legacy_connection_handling, instance_writer: false, default: true + ++ # Application configurable boolean that instructs the YAML Coder to use ++ # an unsafe load if set to true. ++ mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false ++ ++ # Application configurable array that provides additional permitted classes ++ # to Psych safe_load in the YAML Coder ++ mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [] ++ + self.filter_attributes = [] + + def self.connection_handler +-- +2.33.0 + diff --git a/CVE-2022-44566-pre1.patch b/CVE-2022-44566-pre1.patch new file mode 100644 index 0000000..2020089 --- /dev/null +++ b/CVE-2022-44566-pre1.patch @@ -0,0 +1,25 @@ +From fbb7f0b407c96cb38fba6b2e8cb8ce12252738da Mon Sep 17 00:00:00 2001 +From: Jean Boussier +Date: Wed, 13 Jul 2022 18:59:49 +0200 +Subject: [PATCH 1/1] Allow Symbol by default in YAML columns + +--- + activerecord/lib/active_record/core.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/activerecord-6.1.4.1/lib/active_record/core.rb b/activerecord-6.1.4.1/lib/active_record/core.rb +index 379cae1830..9f1584d46b 100644 +--- a/activerecord-6.1.4.1/lib/active_record/core.rb ++++ b/activerecord-6.1.4.1/lib/active_record/core.rb +@@ -161,7 +161,7 @@ def self.configurations + + # Application configurable array that provides additional permitted classes + # to Psych safe_load in the YAML Coder +- mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [] ++ mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [Symbol] + + self.filter_attributes = [] + +-- +2.33.0 + diff --git a/CVE-2022-44566.patch b/CVE-2022-44566.patch new file mode 100644 index 0000000..c1cbb45 --- /dev/null +++ b/CVE-2022-44566.patch @@ -0,0 +1,132 @@ +From 4f44aa9d514e701ada92b5cf08beccf566eeaebf Mon Sep 17 00:00:00 2001 +From: Zack Deveau +Date: Tue, 22 Nov 2022 09:48:59 -0500 +Subject: [PATCH] Added integer width check to PostgreSQL::Quoting + +Given a value outside the range for a 64bit signed integer type +PostgreSQL will treat the column type as numeric. Comparing +integer values against numeric values can result in a slow +sequential scan. + +This behavior is configurable via +ActiveRecord::Base.raise_int_wider_than_64bit which defaults to true. + +[CVE-2022-44566] +--- + .../connection_adapters/postgresql/quoting.rb | 26 +++++++++++++++++ + activerecord/lib/active_record/core.rb | 7 +++++ + .../cases/adapters/postgresql/quoting_test.rb | 28 +++++++++++++++++++ + 3 files changed, 78 insertions(+) + +diff --git a/activerecord-6.1.4.1/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord-6.1.4.1/lib/active_record/connection_adapters/postgresql/quoting.rb +index 3d94d4bb36..4db5f8f528 100644 +--- a/activerecord-6.1.4.1/lib/active_record/connection_adapters/postgresql/quoting.rb ++++ b/activerecord-6.1.4.1/lib/active_record/connection_adapters/postgresql/quoting.rb +@@ -4,6 +4,12 @@ + module ConnectionAdapters + module PostgreSQL + module Quoting ++ class IntegerOutOf64BitRange < StandardError ++ def initialize(msg) ++ super(msg) ++ end ++ end ++ + # Escapes binary strings for bytea input to the database. + def escape_bytea(value) + @connection.escape_bytea(value) if value +@@ -120,7 +126,27 @@ def lookup_cast_type(sql_type) + super(query_value("SELECT #{quote(sql_type)}::regtype::oid", "SCHEMA").to_i) + end + ++ def check_int_in_range(value) ++ if value.to_int > 9223372036854775807 || value.to_int < -9223372036854775808 ++ exception = <<~ERROR ++ Provided value outside of the range of a signed 64bit integer. ++ ++ PostgreSQL will treat the column type in question as a numeric. ++ This may result in a slow sequential scan due to a comparison ++ being performed between an integer or bigint value and a numeric value. ++ ++ To allow for this potentially unwanted behavior, set ++ ActiveRecord::Base.raise_int_wider_than_64bit to false. ++ ERROR ++ raise IntegerOutOf64BitRange.new exception ++ end ++ end ++ + def _quote(value) ++ if ActiveRecord::Base.raise_int_wider_than_64bit && value.is_a?(Integer) ++ check_int_in_range(value) ++ end ++ + case value + when OID::Xml::Data + "xml '#{quote_string(value.to_s)}'" +diff --git a/activerecord-6.1.4.1/lib/active_record/core.rb b/activerecord-6.1.4.1/lib/active_record/core.rb +index 9f1584d46b..d3bfd4929e 100644 +--- a/activerecord-6.1.4.1/lib/active_record/core.rb ++++ b/activerecord-6.1.4.1/lib/active_record/core.rb +@@ -163,6 +163,13 @@ def self.configurations + # to Psych safe_load in the YAML Coder + mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [Symbol] + ++ ## ++ # :singleton-method: ++ # Application configurable boolean that denotes whether or not to raise ++ # an exception when the PostgreSQLAdapter is provided with an integer that is ++ # wider than signed 64bit representation ++ mattr_accessor :raise_int_wider_than_64bit, instance_writer: false, default: true ++ + self.filter_attributes = [] + + def self.connection_handler +diff --git a/test/cases/adapters/postgresql/quoting_test.rb b/test/cases/adapters/postgresql/quoting_test.rb +index d571355a9c..125565f9c8 100644 +--- a/test/cases/adapters/postgresql/quoting_test.rb ++++ b/test/cases/adapters/postgresql/quoting_test.rb +@@ -8,6 +8,7 @@ + class QuotingTest < ActiveRecord::PostgreSQLTestCase + def setup + @conn = ActiveRecord::Base.connection ++ @raise_int_wider_than_64bit = ActiveRecord::Base.raise_int_wider_than_64bit + end + + def test_type_cast_true +@@ -44,6 +45,33 @@ def test_quote_table_name_with_spaces + value = "user posts" + assert_equal "\"user posts\"", @conn.quote_table_name(value) + end ++ ++ def test_raise_when_int_is_wider_than_64bit ++ value = 9223372036854775807 + 1 ++ assert_raise ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting::IntegerOutOf64BitRange do ++ @conn.quote(value) ++ end ++ ++ value = -9223372036854775808 - 1 ++ assert_raise ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting::IntegerOutOf64BitRange do ++ @conn.quote(value) ++ end ++ end ++ ++ def test_do_not_raise_when_int_is_not_wider_than_64bit ++ value = 9223372036854775807 ++ assert_equal "9223372036854775807", @conn.quote(value) ++ ++ value = -9223372036854775808 ++ assert_equal "-9223372036854775808", @conn.quote(value) ++ end ++ ++ def test_do_not_raise_when_raise_int_wider_than_64bit_is_false ++ ActiveRecord::Base.raise_int_wider_than_64bit = false ++ value = 9223372036854775807 + 1 ++ assert_equal "9223372036854775808", @conn.quote(value) ++ ActiveRecord::Base.raise_int_wider_than_64bit = @raise_int_wider_than_64bit ++ end + end + end + end +-- +2.35.1 + diff --git a/CVE-2023-22794.patch b/CVE-2023-22794.patch new file mode 100644 index 0000000..3bebfef --- /dev/null +++ b/CVE-2023-22794.patch @@ -0,0 +1,122 @@ +From 3db858cbc99e332e6f209d50be2b7420211f4c33 Mon Sep 17 00:00:00 2001 +From: John Hawthorn +Date: Tue, 6 Sep 2022 15:49:26 -0700 +Subject: [PATCH] Make sanitize_as_sql_comment more strict + +Though this method was likely never meant to take user input, it was +attempting sanitization. That sanitization could be bypassed with +carefully crafted input. + +This commit makes the sanitization more robust by replacing any +occurrances of "/*" or "*/" with "/ *" or "* /". It also performs a +first pass to remove one surrounding comment to avoid compatibility +issues for users relying on the existing removal. + +This also clarifies in the documentation of annotate that it should not +be provided user input. + +[CVE-2023-22794] +--- + .../connection_adapters/abstract/quoting.rb | 11 ++++++++++- + .../lib/active_record/relation/query_methods.rb | 2 ++ + activerecord/test/cases/annotate_test.rb | 11 ++++++++--- + activerecord/test/cases/relation_test.rb | 10 +++------- + 4 files changed, 23 insertions(+), 11 deletions(-) + +diff --git a/activerecord-6.1.4.1/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord-6.1.4.1/lib/active_record/connection_adapters/abstract/quoting.rb +index 143cd32606..aac5bfe0a0 100644 +--- a/activerecord-6.1.4.1/lib/active_record/connection_adapters/abstract/quoting.rb ++++ b/activerecord-6.1.4.1/lib/active_record/connection_adapters/abstract/quoting.rb +@@ -138,7 +138,16 @@ def quoted_binary(value) # :nodoc: + end + + def sanitize_as_sql_comment(value) # :nodoc: +- value.to_s.gsub(%r{ (/ (?: | \g<1>) \*) \+? \s* | \s* (\* (?: | \g<2>) /) }x, "") ++ # Sanitize a string to appear within a SQL comment ++ # For compatibility, this also surrounding "/*+", "/*", and "*/" ++ # charcacters, possibly with single surrounding space. ++ # Then follows that by replacing any internal "*/" or "/ *" with ++ # "* /" or "/ *" ++ comment = value.to_s.dup ++ comment.gsub!(%r{\A\s*/\*\+?\s?|\s?\*/\s*\Z}, "") ++ comment.gsub!("*/", "* /") ++ comment.gsub!("/*", "/ *") ++ comment + end + + def column_name_matcher # :nodoc: +diff --git a/activerecord-6.1.4.1/lib/active_record/relation/query_methods.rb b/activerecord-6.1.4.1/lib/active_record/relation/query_methods.rb +index 5451ebef46..8be5d5b0a1 100644 +--- a/activerecord-6.1.4.1/lib/active_record/relation/query_methods.rb ++++ b/activerecord-6.1.4.1/lib/active_record/relation/query_methods.rb +@@ -1035,6 +1035,8 @@ def skip_preloading! # :nodoc: + # # SELECT "users"."name" FROM "users" /* selecting */ /* user */ /* names */ + # + # The SQL block comment delimiters, "/*" and "*/", will be added automatically. ++ # ++ # Some escaping is performed, however untrusted user input should not be used. + def annotate(*args) + check_if_method_has_arguments!(:annotate, args) + spawn.annotate!(*args) +diff --git a/test/cases/annotate_test.rb b/test/cases/annotate_test.rb +index 4d71d28f83..21b95a97a1 100644 +--- a/test/cases/annotate_test.rb ++++ b/test/cases/annotate_test.rb +@@ -18,17 +18,22 @@ def test_annotate_wraps_content_in_an_inline_comment + def test_annotate_is_sanitized + quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts") + +- assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do ++ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \* /foo/ \* \*/}i) do + posts = Post.select(:id).annotate("*/foo/*") + assert posts.first + end + +- assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do ++ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \*\* //foo// \*\* \*/}i) do + posts = Post.select(:id).annotate("**//foo//**") + assert posts.first + end + +- assert_sql(%r{\ASELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/ /\* bar \*/}i) do ++ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \* \* //foo// \* \* \*/}i) do ++ posts = Post.select(:id).annotate("* *//foo//* *") ++ assert posts.first ++ end ++ ++ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \* /foo/ \* \*/ /\* \* /bar \*/}i) do + posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar") + assert posts.first + end +diff --git a/test/cases/relation_test.rb b/test/cases/relation_test.rb +index ba0d96b68c..48b752a127 100644 +--- a/test/cases/relation_test.rb ++++ b/test/cases/relation_test.rb +@@ -345,7 +345,7 @@ def test_relation_with_annotation_chains_sql_comments + + def test_relation_with_annotation_filters_sql_comment_delimiters + post_with_annotation = Post.where(id: 1).annotate("**//foo//**") +- assert_match %r{= 1 /\* foo \*/}, post_with_annotation.to_sql ++ assert_includes post_with_annotation.to_sql, "= 1 /* ** //foo// ** */" + end + + def test_relation_with_annotation_includes_comment_in_count_query +@@ -367,13 +367,9 @@ def test_relation_without_annotation_does_not_include_an_empty_comment + + def test_relation_with_optimizer_hints_filters_sql_comment_delimiters + post_with_hint = Post.where(id: 1).optimizer_hints("**//BADHINT//**") +- assert_match %r{BADHINT}, post_with_hint.to_sql +- assert_no_match %r{\*/BADHINT}, post_with_hint.to_sql +- assert_no_match %r{\*//BADHINT}, post_with_hint.to_sql +- assert_no_match %r{BADHINT/\*}, post_with_hint.to_sql +- assert_no_match %r{BADHINT//\*}, post_with_hint.to_sql ++ assert_includes post_with_hint.to_sql, "/*+ ** //BADHINT// ** */" + post_with_hint = Post.where(id: 1).optimizer_hints("/*+ BADHINT */") +- assert_match %r{/\*\+ BADHINT \*/}, post_with_hint.to_sql ++ assert_includes post_with_hint.to_sql, "/*+ BADHINT */" + end + + def test_does_not_duplicate_optimizer_hints_on_merge +-- +2.35.1 + diff --git a/rubygem-activerecord.spec b/rubygem-activerecord.spec index 72a803b..6b1c27d 100644 --- a/rubygem-activerecord.spec +++ b/rubygem-activerecord.spec @@ -2,7 +2,7 @@ Name: rubygem-%{gem_name} Epoch: 1 Version: 6.1.4.1 -Release: 1 +Release: 2 Summary: Object-relational mapper framework (part of Rails) License: MIT URL: http://rubyonrails.org @@ -17,7 +17,10 @@ Source1: activerecord-%{version}-tests.txz # git clone http://github.com/rails/rails.git --no-checkout # cd rails && git archive -v -o rails-6.1.4.1-tools.txz v6.1.4.1 tools/ Source2: rails-%{version}-tools.txz - +Patch0: CVE-2022-44566-pre0.patch +Patch1: CVE-2022-44566-pre1.patch +Patch2: CVE-2022-44566.patch +Patch3: CVE-2023-22794.patch Suggests: %{_bindir}/sqlite3 BuildRequires: rubygems-devel rubygem(bcrypt) rubygem(activesupport) = %{version} BuildRequires: rubygem(activemodel) = %{version} rubygem(builder) rubygem(sqlite3) @@ -38,6 +41,12 @@ Documentation for %{name}. %prep %setup -q -n %{gem_name}-%{version} -b1 -b2 +pushd %{_builddir}/ +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +popd %build gem build ../%{gem_name}-%{version}.gemspec @@ -73,10 +82,13 @@ popd %{gem_instdir}/examples %changelog +* Wed Feb 22 2023 wushaozheng - 1:6.1.4.1-2 +- fix CVE-2022-44566 + * Wed Mar 02 2022 jiangxinyu - 6.1.4.1-1 - update to 6.1.4.1 -* Sat Jan 15 2021 Ge Wang - 5.2.4.4-3 +* Fri Jan 15 2021 Ge Wang - 5.2.4.4-3 - fix check failure * Tue Mar 16 2021 wangyue - 5.2.4.4-2 -- Gitee