diff options
author | Samuel Giddins <[email protected]> | 2023-08-21 09:13:43 -0700 |
---|---|---|
committer | git <[email protected]> | 2023-09-20 02:03:02 +0000 |
commit | e52f9bd41e1c407ac675fa3d1fbaabec854f6968 (patch) | |
tree | dfa011021ed57acb4312e072c520cd318d9f81d4 | |
parent | f0d1b0cc4b5a99de9dc709b8f43d8be8e18c7323 (diff) |
[rubygems/rubygems] Bundler error handling
https://github.com/rubygems/rubygems/commit/63b422b71a
-rw-r--r-- | lib/bundler.rb | 6 | ||||
-rw-r--r-- | lib/bundler/fetcher.rb | 4 | ||||
-rw-r--r-- | lib/bundler/rubygems_integration.rb | 4 | ||||
-rw-r--r-- | lib/rubygems/safe_marshal.rb | 2 | ||||
-rw-r--r-- | lib/rubygems/safe_marshal/reader.rb | 49 | ||||
-rw-r--r-- | lib/rubygems/safe_marshal/visitors/to_ruby.rb | 13 | ||||
-rw-r--r-- | spec/bundler/bundler/bundler_spec.rb | 2 |
7 files changed, 66 insertions, 14 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index 85929c56aa..ee08a2dab8 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -517,7 +517,11 @@ EOF def safe_load_marshal(data) if Gem.respond_to?(:load_safe_marshal) Gem.load_safe_marshal - Gem::SafeMarshal.safe_load(data) + begin + Gem::SafeMarshal.safe_load(data) + rescue Gem::SafeMarshal::Reader::Error, Gem::SafeMarshal::Visitors::ToRuby::Error => e + raise MarshalError, "#{e.class}: #{e.message}" + end else load_marshal(data, :marshal_proc => SafeMarshal.proc) end diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb index 9b64a3c771..5c1eac415e 100644 --- a/lib/bundler/fetcher.rb +++ b/lib/bundler/fetcher.rb @@ -111,7 +111,7 @@ module Bundler spec_file_name = "#{spec.join "-"}.gemspec" uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz") - if uri.scheme == "file" + spec = if uri.scheme == "file" path = Bundler.rubygems.correct_for_windows_path(uri.path) Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path)) elsif cached_spec_path = gemspec_cached_path(spec_file_name) @@ -119,6 +119,8 @@ module Bundler else Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body) end + raise MarshalError, "is #{spec.inspect}" unless spec.is_a?(Gem::Specification) + spec rescue MarshalError raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \ "Your network or your gem server is probably having issues right now." diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index d6f179cc96..f6f0d4a804 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -496,7 +496,9 @@ module Bundler fetcher = gem_remote_fetcher fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri string = fetcher.fetch_path(path) - Bundler.safe_load_marshal(string) + specs = Bundler.safe_load_marshal(string) + raise MarshalError, "Specs #{name} from #{remote} is expected to be an Array but was unexpected class #{specs.class}" unless specs.is_a?(Array) + specs rescue Gem::RemoteFetcher::FetchError # it's okay for prerelease to fail raise unless name == "prerelease_specs" diff --git a/lib/rubygems/safe_marshal.rb b/lib/rubygems/safe_marshal.rb index 215f851167..d308f2d65f 100644 --- a/lib/rubygems/safe_marshal.rb +++ b/lib/rubygems/safe_marshal.rb @@ -62,7 +62,7 @@ module Gem end def self.load(input, permitted_classes: [::Symbol], permitted_symbols: [], permitted_ivars: {}) - root = Reader.new(StringIO.new(input, "r")).read! + root = Reader.new(StringIO.new(input, "r").binmode).read! Visitors::ToRuby.new( permitted_classes: permitted_classes, diff --git a/lib/rubygems/safe_marshal/reader.rb b/lib/rubygems/safe_marshal/reader.rb index 105984ff04..bc0bb62986 100644 --- a/lib/rubygems/safe_marshal/reader.rb +++ b/lib/rubygems/safe_marshal/reader.rb @@ -5,7 +5,16 @@ require_relative "elements" module Gem module SafeMarshal class Reader - class UnconsumedBytesError < StandardError + class Error < StandardError + end + + class UnsupportedVersionError < Error + end + + class UnconsumedBytesError < Error + end + + class NotImplementedError < Error end def initialize(io) @@ -26,7 +35,7 @@ module Gem def read_header v = @io.read(2) - raise "Unsupported marshal version #{v.inspect}, expected #{MARSHAL_VERSION.inspect}" unless v == MARSHAL_VERSION + raise UnsupportedVersionError, "Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}" unless v == MARSHAL_VERSION end def read_byte @@ -80,7 +89,7 @@ module Gem when 91 then read_array # ?[ when 102 then read_float # ?f when 105 then Elements::Integer.new int: read_integer # ?i - when 108 then read_bignum + when 108 then read_bignum # ?l when 111 then read_object # ?o when 117 then read_user_defined # ?u when 123 then read_hash # ?{ @@ -94,7 +103,7 @@ module Gem when "S".ord then read_struct when "C".ord then read_user_class else - raise "Unsupported marshal type discriminator #{type.chr.inspect} (#{type})" + raise Error, "Unknown marshal type discriminator #{type.chr.inspect} (#{type})" end end @@ -177,6 +186,38 @@ module Gem def read_bignum Elements::Bignum.new(sign: read_byte, data: @io.read(read_integer * 2)) end + + def read_extended_object + raise NotImplementedError, "Reading Marshal objects of type extended_object is not implemented" + end + + def read_class + raise NotImplementedError, "Reading Marshal objects of type class is not implemented" + end + + def read_module + raise NotImplementedError, "Reading Marshal objects of type module is not implemented" + end + + def read_class_or_module + raise NotImplementedError, "Reading Marshal objects of type class_or_module is not implemented" + end + + def read_data + raise NotImplementedError, "Reading Marshal objects of type data is not implemented" + end + + def read_regexp + raise NotImplementedError, "Reading Marshal objects of type regexp is not implemented" + end + + def read_struct + raise NotImplementedError, "Reading Marshal objects of type struct is not implemented" + end + + def read_user_class + raise NotImplementedError, "Reading Marshal objects of type user_class is not implemented" + end end end end diff --git a/lib/rubygems/safe_marshal/visitors/to_ruby.rb b/lib/rubygems/safe_marshal/visitors/to_ruby.rb index fb0c75598c..92b647438b 100644 --- a/lib/rubygems/safe_marshal/visitors/to_ruby.rb +++ b/lib/rubygems/safe_marshal/visitors/to_ruby.rb @@ -305,7 +305,10 @@ module Gem::SafeMarshal raise MethodCallError, "Unable to call #{method.inspect} on #{receiver.inspect}, perhaps it is a class using marshal compat, which is not visible in ruby? #{e}" end - class UnpermittedSymbolError < StandardError + class Error < StandardError + end + + class UnpermittedSymbolError < Error def initialize(symbol:, stack:) @symbol = symbol @stack = stack @@ -313,7 +316,7 @@ module Gem::SafeMarshal end end - class UnpermittedIvarError < StandardError + class UnpermittedIvarError < Error def initialize(symbol:, klass:, stack:) @symbol = symbol @klass = klass @@ -322,7 +325,7 @@ module Gem::SafeMarshal end end - class UnpermittedClassError < StandardError + class UnpermittedClassError < Error def initialize(name:, stack:) @name = name @stack = stack @@ -330,10 +333,10 @@ module Gem::SafeMarshal end end - class FormatError < StandardError + class FormatError < Error end - class MethodCallError < StandardError + class MethodCallError < Error end end end diff --git a/spec/bundler/bundler/bundler_spec.rb b/spec/bundler/bundler/bundler_spec.rb index f4c1664620..132ce5c8ad 100644 --- a/spec/bundler/bundler/bundler_spec.rb +++ b/spec/bundler/bundler/bundler_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Bundler do end it "loads simple structure" do - simple_structure = { "name" => [:abc] } + simple_structure = { "name" => [:development] } data = Marshal.dump(simple_structure) expect(Bundler.safe_load_marshal(data)).to eq(simple_structure) end |