summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <nobu@ruby-lang.org>2021-06-04 10:38:43 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2021-07-27 09:25:56 +0900
commit803c60858e42463d33a00950883b17b1c38a2347 (patch)
treef487dd700b4087bda80b55032edaf3d6bb284e3e
parent88e46cf6b83e2ca701cf122756fef9bc2550e845 (diff)
[rubygems/rubygems] Check requirements classes
Mitigate the security risk: https://devcraft.io/2021/01/07/universal-deserialisation-gadget-for-ruby-2-x-3-x.html https://github.com/rubygems/rubygems/commit/141c2f4388
-rw-r--r--lib/rubygems/requirement.rb2
-rw-r--r--test/rubygems/test_gem_requirement.rb34
2 files changed, 36 insertions, 0 deletions
diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb
index 0067f6304a..16de45ad91 100644
--- a/lib/rubygems/requirement.rb
+++ b/lib/rubygems/requirement.rb
@@ -199,6 +199,8 @@ class Gem::Requirement
def marshal_load(array) # :nodoc:
@requirements = array[0]
+
+ raise TypeError, "wrong @requirements" unless Array === @requirements
end
def yaml_initialize(tag, vals) # :nodoc:
diff --git a/test/rubygems/test_gem_requirement.rb b/test/rubygems/test_gem_requirement.rb
index f32d13f3a9..b4367681d0 100644
--- a/test/rubygems/test_gem_requirement.rb
+++ b/test/rubygems/test_gem_requirement.rb
@@ -422,6 +422,40 @@ class TestGemRequirement < Gem::TestCase
assert_requirement_hash_equal "1", "1.0.0"
end
+ class Exploit < RuntimeError
+ end
+
+ def self.exploit(arg)
+ raise Exploit, "arg = #{arg}"
+ end
+
+ def test_marshal_load_attack
+ wa = Net::WriteAdapter.allocate
+ wa.instance_variable_set(:@socket, self.class)
+ wa.instance_variable_set(:@method_id, :exploit)
+ request_set = Gem::RequestSet.allocate
+ request_set.instance_variable_set(:@git_set, "id")
+ request_set.instance_variable_set(:@sets, wa)
+ wa = Net::WriteAdapter.allocate
+ wa.instance_variable_set(:@socket, request_set)
+ wa.instance_variable_set(:@method_id, :resolve)
+ ent = Gem::Package::TarReader::Entry.allocate
+ ent.instance_variable_set(:@read, 0)
+ ent.instance_variable_set(:@header, "aaa")
+ io = Net::BufferedIO.allocate
+ io.instance_variable_set(:@io, ent)
+ io.instance_variable_set(:@debug_output, wa)
+ reader = Gem::Package::TarReader.allocate
+ reader.instance_variable_set(:@io, io)
+ requirement = Gem::Requirement.allocate
+ requirement.instance_variable_set(:@requirements, reader)
+ m = [Gem::SpecFetcher, Gem::Installer, requirement]
+ e = assert_raise(TypeError) do
+ Marshal.load(Marshal.dump(m))
+ end
+ assert_equal(e.message, "wrong @requirements")
+ end
+
# Assert that two requirements are equal. Handles Gem::Requirements,
# strings, arrays, numbers, and versions.