From d40ddfa4cc784f8719c48c11e73a71362db76039 Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Fri, 8 Mar 2019 04:49:51 +0000 Subject: system/ruby: [CVE] secbump, modernise --- system/ruby/APKBUILD | 25 +- system/ruby/ruby-2.5.3-rubygems-v2.patch | 408 +++++++++++++++++++++++++++++++ 2 files changed, 422 insertions(+), 11 deletions(-) create mode 100644 system/ruby/ruby-2.5.3-rubygems-v2.patch (limited to 'system') diff --git a/system/ruby/APKBUILD b/system/ruby/APKBUILD index 18d9bf8d8..7f949cc04 100644 --- a/system/ruby/APKBUILD +++ b/system/ruby/APKBUILD @@ -24,11 +24,18 @@ # 2.5.3-r0: # - CVE-2018-16395 # - CVE-2018-16396 +# 2.5.3-r2: +# - CVE-2019-8320 +# - CVE-2019-8321 +# - CVE-2019-8322 +# - CVE-2019-8323 +# - CVE-2019-8324 +# - CVE-2019-8325 # pkgname=ruby pkgver=2.5.3 _abiver="${pkgver%.*}.0" -pkgrel=1 +pkgrel=2 pkgdesc="An object-oriented language for quick and easy programming" url="https://www.ruby-lang.org/" arch="all" @@ -61,7 +68,9 @@ subpackages="$pkgname-doc $pkgname-dev source="https://cache.ruby-lang.org/pub/ruby/${pkgver%.*}/$pkgname-$pkgver.tar.xz rubygems-avoid-platform-specific-gems.patch test_insns-lower-recursion-depth.patch - fix-get_main_stack.patch" + fix-get_main_stack.patch + ruby-2.5.3-rubygems-v2.patch + " replaces="ruby-gems" _gemdir="/usr/lib/ruby/gems/$_abiver" @@ -83,14 +92,10 @@ done prepare() { default_prepare - - cd "$builddir" autoconf } build() { - cd "$builddir" - # -fomit-frame-pointer makes ruby segfault, see gentoo bug #150413 # In many places aliasing rules are broken; play it safe # as it's risky with newer compilers to leave it as it is. @@ -111,7 +116,7 @@ build() { --sysconfdir=/etc \ --mandir=/usr/share/man \ --infodir=/usr/share/info \ - --with-sitedir='/usr/local/lib/site_ruby' \ + --with-sitedir="/usr/local/lib/site_ruby" \ --with-search-path="/usr/lib/site_ruby/\$(ruby_ver)/$_arch-linux" \ --enable-pthread \ --disable-rpath \ @@ -121,13 +126,10 @@ build() { } check() { - cd "$builddir" make test } package() { - cd "$builddir" - make DESTDIR="$pkgdir" install install -m 644 -D COPYING \ @@ -317,4 +319,5 @@ _mvgem() { sha512sums="6dcae0e8d0bacdb2cbde636e2030596308b5af53f2eb85d3adccb67b02e6f8f9751e8117d12f8484829fdd9d995f6e327f701d9b433bcf94f1f59d13a1fd7518 ruby-2.5.3.tar.xz cfdc5ea3b2e2ea69c51f38e8e2180cb1dc27008ca55cc6301f142ebafdbab31c3379b3b6bba9ff543153876dd98ed2ad194df3255b7ea77a62e931c935f80538 rubygems-avoid-platform-specific-gems.patch 814fe6359505b70d8ff680adf22f20a74b4dbd3fecc9a63a6c2456ee9824257815929917b6df5394ed069a6869511b8c6dce5b95b4acbbb7867c1f3a975a0150 test_insns-lower-recursion-depth.patch -8d730f02f76e53799f1c220eb23e3d2305940bb31216a7ab1e42d3256149c0721c7d173cdbfe505023b1af2f5cb3faa233dcc1b5d560fa8f980c17c2d29a9d81 fix-get_main_stack.patch" +8d730f02f76e53799f1c220eb23e3d2305940bb31216a7ab1e42d3256149c0721c7d173cdbfe505023b1af2f5cb3faa233dcc1b5d560fa8f980c17c2d29a9d81 fix-get_main_stack.patch +4f374a8bce1f5137e155d79aa06086d25c3be45f90d8dbebc9f4ee2fb71dd5fe4a3bc1f7b922e784cbb9054f575155c1ad921062b762eb372306dabe9ff7951e ruby-2.5.3-rubygems-v2.patch" diff --git a/system/ruby/ruby-2.5.3-rubygems-v2.patch b/system/ruby/ruby-2.5.3-rubygems-v2.patch new file mode 100644 index 000000000..cf2b2c7f1 --- /dev/null +++ b/system/ruby/ruby-2.5.3-rubygems-v2.patch @@ -0,0 +1,408 @@ +diff --git lib/rubygems.rb lib/rubygems.rb +index 2762bfcb88..cd7434ca87 100644 +--- a/lib/rubygems.rb ++++ b/lib/rubygems.rb +@@ -10,7 +10,7 @@ + require 'thread' + + module Gem +- VERSION = "2.7.6" ++ VERSION = "2.7.6.1" + end + + # Must be first since it unloads the prelude from 1.9.2 +diff --git lib/rubygems/command_manager.rb lib/rubygems/command_manager.rb +index 887272378e..3bee1c30a4 100644 +--- a/lib/rubygems/command_manager.rb ++++ b/lib/rubygems/command_manager.rb +@@ -7,6 +7,7 @@ + + require 'rubygems/command' + require 'rubygems/user_interaction' ++require 'rubygems/text' + + ## + # The command manager registers and installs all the individual sub-commands +@@ -32,6 +33,7 @@ + + class Gem::CommandManager + ++ include Gem::Text + include Gem::UserInteraction + + BUILTIN_COMMANDS = [ # :nodoc: +@@ -140,12 +142,12 @@ def command_names + def run(args, build_args=nil) + process_args(args, build_args) + rescue StandardError, Timeout::Error => ex +- alert_error "While executing gem ... (#{ex.class})\n #{ex}" ++ alert_error clean_text("While executing gem ... (#{ex.class})\n #{ex}") + ui.backtrace ex + + terminate_interaction(1) + rescue Interrupt +- alert_error "Interrupted" ++ alert_error clean_text("Interrupted") + terminate_interaction(1) + end + +@@ -163,7 +165,7 @@ def process_args(args, build_args=nil) + say Gem::VERSION + terminate_interaction 0 + when /^-/ then +- alert_error "Invalid option: #{args.first}. See 'gem --help'." ++ alert_error clean_text("Invalid option: #{args.first}. See 'gem --help'.") + terminate_interaction 1 + else + cmd_name = args.shift.downcase +@@ -212,7 +214,7 @@ def load_and_instantiate(command_name) + rescue Exception => e + e = load_error if load_error + +- alert_error "Loading command: #{command_name} (#{e.class})\n\t#{e}" ++ alert_error clean_text("Loading command: #{command_name} (#{e.class})\n\t#{e}") + ui.backtrace e + end + end +diff --git lib/rubygems/commands/owner_command.rb lib/rubygems/commands/owner_command.rb +index 637b5bdc4d..cac6c5a17d 100644 +--- a/lib/rubygems/commands/owner_command.rb ++++ b/lib/rubygems/commands/owner_command.rb +@@ -2,8 +2,11 @@ + require 'rubygems/command' + require 'rubygems/local_remote_options' + require 'rubygems/gemcutter_utilities' ++require 'rubygems/text' + + class Gem::Commands::OwnerCommand < Gem::Command ++ ++ include Gem::Text + include Gem::LocalRemoteOptions + include Gem::GemcutterUtilities + +@@ -64,7 +67,7 @@ def show_owners name + end + + with_response response do |resp| +- owners = Gem::SafeYAML.load resp.body ++ owners = Gem::SafeYAML.load clean_text(resp.body) + + say "Owners for gem: #{name}" + owners.each do |owner| +diff --git lib/rubygems/gemcutter_utilities.rb lib/rubygems/gemcutter_utilities.rb +index 7c6d6bb364..623d9301b5 100644 +--- a/lib/rubygems/gemcutter_utilities.rb ++++ b/lib/rubygems/gemcutter_utilities.rb +@@ -1,11 +1,14 @@ + # frozen_string_literal: true + require 'rubygems/remote_fetcher' ++require 'rubygems/text' + + ## + # Utility methods for using the RubyGems API. + + module Gem::GemcutterUtilities + ++ include Gem::Text ++ + # TODO: move to Gem::Command + OptionParser.accept Symbol do |value| + value.to_sym +@@ -145,13 +148,13 @@ def with_response response, error_prefix = nil + if block_given? then + yield response + else +- say response.body ++ say clean_text(response.body) + end + else + message = response.body + message = "#{error_prefix}: #{message}" if error_prefix + +- say message ++ say clean_text(message) + terminate_interaction 1 # TODO: question this + end + end +diff --git lib/rubygems/installer.rb lib/rubygems/installer.rb +index ee5fedeb64..904d5a0c7c 100644 +--- a/lib/rubygems/installer.rb ++++ b/lib/rubygems/installer.rb +@@ -707,9 +707,26 @@ def verify_gem_home(unpack = false) # :nodoc: + unpack or File.writable?(gem_home) + end + +- def verify_spec_name +- return if spec.name =~ Gem::Specification::VALID_NAME_PATTERN +- raise Gem::InstallError, "#{spec} has an invalid name" ++ def verify_spec ++ unless spec.name =~ Gem::Specification::VALID_NAME_PATTERN ++ raise Gem::InstallError, "#{spec} has an invalid name" ++ end ++ ++ if spec.raw_require_paths.any?{|path| path =~ /\r\n|\r|\n/ } ++ raise Gem::InstallError, "#{spec} has an invalid require_paths" ++ end ++ ++ if spec.extensions.any?{|ext| ext =~ /\r\n|\r|\n/ } ++ raise Gem::InstallError, "#{spec} has an invalid extensions" ++ end ++ ++ unless spec.specification_version.to_s =~ /\A\d+\z/ ++ raise Gem::InstallError, "#{spec} has an invalid specification_version" ++ end ++ ++ if spec.dependencies.any? {|dep| dep.type =~ /\r\n|\r|\n/ || dep.name =~ /\r\n|\r|\n/ } ++ raise Gem::InstallError, "#{spec} has an invalid dependencies" ++ end + end + + ## +@@ -836,10 +853,12 @@ def dir + def pre_install_checks + verify_gem_home options[:unpack] + ++ # The name and require_paths must be verified first, since it could contain ++ # ruby code that would be eval'ed in #ensure_loadable_spec ++ verify_spec ++ + ensure_loadable_spec + +- verify_spec_name +- + if options[:install_as_default] + Gem.ensure_default_gem_subdirectories gem_home + else +diff --git lib/rubygems/package.rb lib/rubygems/package.rb +index b924122827..b472b97a07 100644 +--- a/lib/rubygems/package.rb ++++ b/lib/rubygems/package.rb +@@ -425,6 +425,16 @@ def install_location filename, destination_dir # :nodoc: + raise Gem::Package::PathError.new(destination, destination_dir) unless + destination.start_with? destination_dir + '/' + ++ begin ++ real_destination = File.expand_path(File.realpath(destination)) ++ rescue ++ # it's fine if the destination doesn't exist, because rm -rf'ing it can't cause any damage ++ nil ++ else ++ raise Gem::Package::PathError.new(real_destination, destination_dir) unless ++ real_destination.start_with? destination_dir + '/' ++ end ++ + destination.untaint + destination + end +diff --git lib/rubygems/user_interaction.rb lib/rubygems/user_interaction.rb +index cacd782e08..eff8f9533c 100644 +--- a/lib/rubygems/user_interaction.rb ++++ b/lib/rubygems/user_interaction.rb +@@ -6,6 +6,7 @@ + #++ + + require 'rubygems/util' ++require 'rubygems/text' + + ## + # Module that defines the default UserInteraction. Any class including this +@@ -13,6 +14,8 @@ + + module Gem::DefaultUserInteraction + ++ include Gem::Text ++ + ## + # The default UI is a class variable of the singleton class for this + # module. +@@ -160,8 +163,8 @@ def terminate_interaction exit_code = 0 + # Calls +say+ with +msg+ or the results of the block if really_verbose + # is true. + +- def verbose msg = nil +- say(msg || yield) if Gem.configuration.really_verbose ++ def verbose(msg = nil) ++ say(clean_text(msg || yield)) if Gem.configuration.really_verbose + end + end + +diff --git test/rubygems/test_gem_installer.rb test/rubygems/test_gem_installer.rb +index 93b0482407..a47a307049 100644 +--- a/test/rubygems/test_gem_installer.rb ++++ b/test/rubygems/test_gem_installer.rb +@@ -1474,6 +1474,114 @@ def spec.validate; end + end + end + ++ def test_pre_install_checks_malicious_name_before_eval ++ spec = util_spec "malicious\n::Object.const_set(:FROM_EVAL, true)#", '1' ++ def spec.full_name # so the spec is buildable ++ "malicious-1" ++ end ++ def spec.validate(*args); end ++ ++ util_build_gem spec ++ ++ gem = File.join(@gemhome, 'cache', spec.file_name) ++ ++ use_ui @ui do ++ @installer = Gem::Installer.at gem ++ e = assert_raises Gem::InstallError do ++ @installer.pre_install_checks ++ end ++ assert_equal "# has an invalid name", e.message ++ end ++ refute defined?(::Object::FROM_EVAL) ++ end ++ ++ def test_pre_install_checks_malicious_require_paths_before_eval ++ spec = util_spec "malicious", '1' ++ def spec.full_name # so the spec is buildable ++ "malicious-1" ++ end ++ def spec.validate(*args); end ++ spec.require_paths = ["malicious\n``"] ++ ++ util_build_gem spec ++ ++ gem = File.join(@gemhome, 'cache', spec.file_name) ++ ++ use_ui @ui do ++ @installer = Gem::Installer.at gem ++ e = assert_raises Gem::InstallError do ++ @installer.pre_install_checks ++ end ++ assert_equal "# has an invalid require_paths", e.message ++ end ++ end ++ ++ def test_pre_install_checks_malicious_extensions_before_eval ++ skip "mswin environment disallow to create file contained the carriage return code." if Gem.win_platform? ++ ++ spec = util_spec "malicious", '1' ++ def spec.full_name # so the spec is buildable ++ "malicious-1" ++ end ++ def spec.validate(*args); end ++ spec.extensions = ["malicious\n``"] ++ ++ util_build_gem spec ++ ++ gem = File.join(@gemhome, 'cache', spec.file_name) ++ ++ use_ui @ui do ++ @installer = Gem::Installer.at gem ++ e = assert_raises Gem::InstallError do ++ @installer.pre_install_checks ++ end ++ assert_equal "# has an invalid extensions", e.message ++ end ++ end ++ ++ def test_pre_install_checks_malicious_specification_version_before_eval ++ spec = util_spec "malicious", '1' ++ def spec.full_name # so the spec is buildable ++ "malicious-1" ++ end ++ def spec.validate(*args); end ++ spec.specification_version = "malicious\n``" ++ ++ util_build_gem spec ++ ++ gem = File.join(@gemhome, 'cache', spec.file_name) ++ ++ use_ui @ui do ++ @installer = Gem::Installer.at gem ++ e = assert_raises Gem::InstallError do ++ @installer.pre_install_checks ++ end ++ assert_equal "# has an invalid specification_version", e.message ++ end ++ end ++ ++ def test_pre_install_checks_malicious_dependencies_before_eval ++ spec = util_spec "malicious", '1' ++ def spec.full_name # so the spec is buildable ++ "malicious-1" ++ end ++ def spec.validate(*args); end ++ spec.add_dependency "b\nfoo", '> 5' ++ ++ util_build_gem spec ++ ++ gem = File.join(@gemhome, 'cache', spec.file_name) ++ ++ use_ui @ui do ++ @installer = Gem::Installer.at gem ++ @installer.ignore_dependencies = true ++ e = assert_raises Gem::InstallError do ++ @installer.pre_install_checks ++ end ++ assert_equal "# has an invalid dependencies", e.message ++ end ++ end ++ + def test_shebang + util_make_exec @spec, "#!/usr/bin/ruby" + +diff --git test/rubygems/test_gem_package.rb test/rubygems/test_gem_package.rb +index d1664cf285..0b03ee2e0c 100644 +--- a/test/rubygems/test_gem_package.rb ++++ b/test/rubygems/test_gem_package.rb +@@ -480,6 +480,42 @@ def test_extract_symlink_parent + "#{destination_subdir} is not allowed", e.message) + end + ++ def test_extract_symlink_parent_doesnt_delete_user_dir ++ skip if RUBY_VERSION <= "1.8.7" ++ ++ package = Gem::Package.new @gem ++ ++ # Extract into a subdirectory of @destination; if this test fails it writes ++ # a file outside destination_subdir, but we want the file to remain inside ++ # @destination so it will be cleaned up. ++ destination_subdir = File.join @destination, 'subdir' ++ FileUtils.mkdir_p destination_subdir ++ ++ destination_user_dir = File.join @destination, 'user' ++ destination_user_subdir = File.join destination_user_dir, 'dir' ++ FileUtils.mkdir_p destination_user_subdir ++ ++ tgz_io = util_tar_gz do |tar| ++ tar.add_symlink 'link', destination_user_dir, 16877 ++ tar.add_symlink 'link/dir', '.', 16877 ++ end ++ ++ e = assert_raises(Gem::Package::PathError, Errno::EACCES) do ++ package.extract_tar_gz tgz_io, destination_subdir ++ end ++ ++ assert_path_exists destination_user_subdir ++ ++ if Gem::Package::PathError === e ++ assert_equal("installing into parent path #{destination_user_subdir} of " + ++ "#{destination_subdir} is not allowed", e.message) ++ elsif win_platform? ++ skip "symlink - must be admin with no UAC on Windows" ++ else ++ raise e ++ end ++ end ++ + def test_extract_tar_gz_directory + package = Gem::Package.new @gem + +diff --git test/rubygems/test_gem_text.rb test/rubygems/test_gem_text.rb +index 04f3f605e8..8ce6df94bb 100644 +--- a/test/rubygems/test_gem_text.rb ++++ b/test/rubygems/test_gem_text.rb +@@ -85,4 +85,9 @@ def test_truncate_text + s = "ab" * 500_001 + assert_equal "Truncating desc to 1,000,000 characters:\n#{s[0, 1_000_000]}", truncate_text(s, "desc", 1_000_000) + end ++ ++ def test_clean_text ++ assert_equal ".]2;nyan.", clean_text("\e]2;nyan\a") ++ end ++ + end -- cgit v1.2.3-70-g09d2