From 6a7cb043e9908ff69d3f9d887b63a9d1bd11180b Mon Sep 17 00:00:00 2001 From: starlet-dx <15929766099@163.com> Date: Mon, 18 Nov 2024 15:12:23 +0800 Subject: [PATCH] Fix CVE-2022-45442 --- Fix-broken-spec.patch | 23 +++++++ ...errors-now-extend-Sinatra-Error-test.patch | 66 +++++++++++++++++++ ...atra-errors-now-extend-Sinatra-Error.patch | 57 ++++++++++++++++ backport-CVE-2022-45442-test.patch | 40 +++++++++++ backport-CVE-2022-45442.patch | 51 ++++++++++++++ rubygem-sinatra.spec | 22 ++++++- 6 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 Fix-broken-spec.patch create mode 100644 Internal-Sinatra-errors-now-extend-Sinatra-Error-test.patch create mode 100644 Internal-Sinatra-errors-now-extend-Sinatra-Error.patch create mode 100644 backport-CVE-2022-45442-test.patch create mode 100644 backport-CVE-2022-45442.patch diff --git a/Fix-broken-spec.patch b/Fix-broken-spec.patch new file mode 100644 index 0000000..f047fca --- /dev/null +++ b/Fix-broken-spec.patch @@ -0,0 +1,23 @@ +From 5baa1c8ddcadfdfe07b74c2a72fc9a29121851fd Mon Sep 17 00:00:00 2001 +From: Jordan Owens +Date: Sun, 22 Jan 2023 19:28:40 -0500 +Subject: [PATCH] Fix broken spec + +HTTP ranges with non decimal characters is treated as range 0..0 as of Rack 2.2.6.2. +--- + test/static_test.rb | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/test/static_test.rb b/test/static_test.rb +index 232cd21c5d..0022f088b4 100644 +--- a/test/static_test.rb ++++ b/test/static_test.rb +@@ -164,7 +164,7 @@ def assert_valid_range(http_range, range, path, file) + end + + it 'correctly ignores syntactically invalid range requests' do +- ["bytes=45-40", "bytes=IV-LXVI", "octets=10-20", "bytes=", "bytes=3-1,4-5"].each do |http_range| ++ ["bytes=45-40", "octets=10-20", "bytes=", "bytes=3-1,4-5"].each do |http_range| + request = Rack::MockRequest.new(@app) + response = request.get("/#{File.basename(__FILE__)}", 'HTTP_RANGE' => http_range) + \ No newline at end of file diff --git a/Internal-Sinatra-errors-now-extend-Sinatra-Error-test.patch b/Internal-Sinatra-errors-now-extend-Sinatra-Error-test.patch new file mode 100644 index 0000000..2b21c21 --- /dev/null +++ b/Internal-Sinatra-errors-now-extend-Sinatra-Error-test.patch @@ -0,0 +1,66 @@ +From d8c35ce7bc6320e5805b106e1bec39d0b64b9306 Mon Sep 17 00:00:00 2001 +From: Jordan Owens +Date: Thu, 31 Jan 2019 22:32:45 -0500 +Subject: [PATCH] Internal Sinatra errors now extend Sinatra::Error + +--- + test/mapped_error_test.rb | 6 +++--- + test/result_test.rb | 15 +++++++++++++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/test/mapped_error_test.rb b/test/mapped_error_test.rb +index cb158a2..562e509 100644 +--- a/test/mapped_error_test.rb ++++ b/test/mapped_error_test.rb +@@ -6,15 +6,15 @@ end + class FooNotFound < Sinatra::NotFound + end + +-class FooSpecialError < RuntimeError ++class FooSpecialError < Sinatra::Error + def http_status; 501 end + end + +-class FooStatusOutOfRangeError < RuntimeError ++class FooStatusOutOfRangeError < Sinatra::Error + def code; 4000 end + end + +-class FooWithCode < RuntimeError ++class FooWithCode < Sinatra::Error + def code; 419 end + end + +diff --git a/test/result_test.rb b/test/result_test.rb +index cbb7813..cc9990f 100644 +--- a/test/result_test.rb ++++ b/test/result_test.rb +@@ -1,5 +1,9 @@ + require File.expand_path('../helper', __FILE__) + ++class ThirdPartyError < RuntimeError ++ def http_status; 400 end ++end ++ + class ResultTest < Minitest::Test + it "sets response.body when result is a String" do + mock_app { get('/') { 'Hello World' } } +@@ -73,4 +77,15 @@ class ResultTest < Minitest::Test + assert_equal 205, status + assert_equal '', body + end ++ ++ it "sets status to 500 when raised error is not Sinatra::Error" do ++ mock_app do ++ set :raise_errors, false ++ get('/') { raise ThirdPartyError } ++ end ++ ++ get '/' ++ assert_equal 500, status ++ assert_equal '

Internal Server Error

', body ++ end + end +-- +2.27.0 + diff --git a/Internal-Sinatra-errors-now-extend-Sinatra-Error.patch b/Internal-Sinatra-errors-now-extend-Sinatra-Error.patch new file mode 100644 index 0000000..0ec3ae8 --- /dev/null +++ b/Internal-Sinatra-errors-now-extend-Sinatra-Error.patch @@ -0,0 +1,57 @@ +From 084cf2ade353d3bf5f1a76aade87efd2f887bdd5 Mon Sep 17 00:00:00 2001 +From: Jordan Owens +Date: Thu, 31 Jan 2019 22:32:45 -0500 +Subject: [PATCH] Internal Sinatra errors now extend Sinatra::Error + +--- + lib/sinatra/base.rb | 22 +++++++++++++--------- + 1 file changed, 13 insertions(+), 9 deletions(-) + +diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb +index f5d7729..aebd025 100644 +--- a/lib/sinatra/base.rb ++++ b/lib/sinatra/base.rb +@@ -233,11 +233,14 @@ module Sinatra + end + end + +- class BadRequest < TypeError #:nodoc: ++ class Error < StandardError #:nodoc: ++ end ++ ++ class BadRequest < Error #:nodoc: + def http_status; 400 end + end + +- class NotFound < NameError #:nodoc: ++ class NotFound < Error #:nodoc: + def http_status; 404 end + end + +@@ -1114,15 +1117,16 @@ module Sinatra + end + @env['sinatra.error'] = boom + +- if boom.respond_to? :http_status +- status(boom.http_status) +- elsif settings.use_code? and boom.respond_to? :code and boom.code.between? 400, 599 +- status(boom.code) +- else +- status(500) ++ http_status = if boom.kind_of? Sinatra::Error ++ if boom.respond_to? :http_status ++ boom.http_status ++ elsif settings.use_code? && boom.respond_to?(:code) ++ boom.code ++ end + end + +- status(500) unless status.between? 400, 599 ++ http_status = 500 unless http_status && http_status.between?(400, 599) ++ status(http_status) + + boom_message = boom.message if boom.message && boom.message != boom.class.name + if server_error? +-- +2.27.0 + diff --git a/backport-CVE-2022-45442-test.patch b/backport-CVE-2022-45442-test.patch new file mode 100644 index 0000000..51009da --- /dev/null +++ b/backport-CVE-2022-45442-test.patch @@ -0,0 +1,40 @@ +From 1808bcdf3424eab0c659ef2d0e85579aab977a1a Mon Sep 17 00:00:00 2001 +From: namusyaka +Date: Wed, 23 Nov 2022 22:24:02 +0900 +Subject: [PATCH] escape filename in the Content-Disposition header + +According the multipart form data spec in WHATWG living standard. +Ref: https://html.spec.whatwg.org/#multipart-form-data + +Origin: +https://github.com/sinatra/sinatra/commit/1808bcdf3424eab0c659ef2d0e85579aab977a1a +--- + test/helpers_test.rb | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/test/helpers_test.rb b/test/helpers_test.rb +index 463a21d..7201aab 100644 +--- a/test/helpers_test.rb ++++ b/test/helpers_test.rb +@@ -781,6 +781,18 @@ class HelpersTest < Minitest::Test + assert_equal '', body + end + ++ it 'escapes filename in the Content-Disposition header according to the multipart form data spec in WHATWG living standard' do ++ mock_app do ++ get('/attachment') do ++ attachment "test.xml\";\r\next=.txt" ++ response.write("") ++ end ++ end ++ ++ get '/attachment' ++ assert_equal 'attachment; filename="test.xml%22;%0D%0Aext=.txt"', response['Content-Disposition'] ++ assert_equal '', body ++ end + end + + describe 'send_file' do +-- +2.47.0 + diff --git a/backport-CVE-2022-45442.patch b/backport-CVE-2022-45442.patch new file mode 100644 index 0000000..0386977 --- /dev/null +++ b/backport-CVE-2022-45442.patch @@ -0,0 +1,51 @@ +From 1808bcdf3424eab0c659ef2d0e85579aab977a1a Mon Sep 17 00:00:00 2001 +From: namusyaka +Date: Wed, 23 Nov 2022 22:24:02 +0900 +Subject: [PATCH] escape filename in the Content-Disposition header + +According the multipart form data spec in WHATWG living standard. +Ref: https://html.spec.whatwg.org/#multipart-form-data + +Origin: +https://github.com/sinatra/sinatra/commit/1808bcdf3424eab0c659ef2d0e85579aab977a1a +--- + lib/sinatra/base.rb | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb +index f5d7729..b20a1f7 100644 +--- a/lib/sinatra/base.rb ++++ b/lib/sinatra/base.rb +@@ -357,16 +357,23 @@ module Sinatra + response['Content-Type'] = mime_type + end + ++ # https://html.spec.whatwg.org/#multipart-form-data ++ MULTIPART_FORM_DATA_REPLACEMENT_TABLE = { ++ '"' => '%22', ++ "\r" => '%0D', ++ "\n" => '%0A' ++ }.freeze ++ + # Set the Content-Disposition to "attachment" with the specified filename, + # instructing the user agents to prompt to save. + def attachment(filename = nil, disposition = :attachment) + response['Content-Disposition'] = disposition.to_s.dup +- if filename +- params = '; filename="%s"' % File.basename(filename) +- response['Content-Disposition'] << params +- ext = File.extname(filename) +- content_type(ext) unless response['Content-Type'] or ext.empty? +- end ++ return unless filename ++ ++ params = format('; filename="%s"', File.basename(filename).gsub(/["\r\n]/, MULTIPART_FORM_DATA_REPLACEMENT_TABLE)) ++ response['Content-Disposition'] << params ++ ext = File.extname(filename) ++ content_type(ext) unless response['Content-Type'] || ext.empty? + end + + # Use the contents of the file at +path+ as the response body. +-- +2.47.0 + diff --git a/rubygem-sinatra.spec b/rubygem-sinatra.spec index b17e2ac..d869e00 100644 --- a/rubygem-sinatra.spec +++ b/rubygem-sinatra.spec @@ -3,7 +3,7 @@ Summary: Ruby-based web application framework Name: rubygem-%{gem_name} Version: 2.0.8.1 -Release: 1 +Release: 3 License: MIT URL: http://www.sinatrarb.com/ Source0: https://rubygems.org/gems/%{gem_name}-%{version}.gem @@ -13,6 +13,14 @@ Source1: %{gem_name}-%{version}-test.tar.gz # Fix test failure due to Rack 2.2.2 incompatibility. # https://github.com/sinatra/sinatra/pull/1605 Patch0: rubygem-sinatra-2.0.8.1-Fix-failing-tests.patch +Patch1: Internal-Sinatra-errors-now-extend-Sinatra-Error-test.patch +Patch2: Internal-Sinatra-errors-now-extend-Sinatra-Error.patch +Patch3: Fix-broken-spec.patch + +# Security fix +Patch3000: backport-CVE-2022-45442.patch +Patch3001: backport-CVE-2022-45442-test.patch + BuildRequires: rubygems-devel ruby(release) ruby >= 2.2.0 %if ! 0%{?bootstrap} BuildRequires: rubygem(rack) >= 2.0 rubygem(rack-protection) = %{version} rubygem(tilt) @@ -37,8 +45,14 @@ This package contains documentation for %{name}. pushd %{_builddir} %patch0 -p1 +%patch1 -p1 +%patch3 -p1 +%patch3001 -p1 popd +%patch2 -p1 +%patch3000 -p1 + %build gem build ../%{gem_name}-%{version}.gemspec %gem_install @@ -82,6 +96,12 @@ popd %{gem_instdir}/examples %changelog +* Mon Nov 18 2024 yaoxin - 1:2.0.8.1-3 +- Fix CVE-2022-45442 + +* Wed Jul 17 2024 jiangxinyu - 1:2.0.8.1-2 +- fix the correctly ignores syntactically invalid range requests test + * Thu Feb 24 2022 liyanan - 2.0.8.1-1 - update to 2.0.8.1