Permalink
Browse files

Fix CVE-2013-4363, remove regexp backtracking

The Gem::Version regexp used backtracking to validate gem versions, but
in a different way than CVE-2013-4287. This could cause excessive CPU
usage when creating Gem::Version objects including when packaging gems.
See CVE-2013-4363.txt (in this commit) for details.

See #626
  • Loading branch information...
1 parent a215515 commit f63bfbc5c7b5725def5fecd6518ce2aa49e12ecd @drbrain drbrain committed Sep 24, 2013
Showing with 76 additions and 13 deletions.
  1. +45 −0 CVE-2013-4363.txt
  2. +9 −0 History.txt
  3. +1 −0 Manifest.txt
  4. +1 −1 lib/rubygems/version.rb
  5. +11 −9 test/rubygems/test_gem_requirement.rb
  6. +9 −3 test/rubygems/test_gem_version.rb
View
@@ -0,0 +1,45 @@
+= Algorithmic complexity vulnerability in RubyGems 2.1.4 and older
+
+The patch for CVE-2013-4287 was insufficiently verified so the combined
+regular expression for verifying gem version remains vulnerable following
+CVE-2013-4287.
+
+RubyGems validates versions with a regular expression that is vulnerable to
+denial of service due to backtracking. For specially crafted RubyGems
+versions attackers can cause denial of service through CPU consumption.
+
+RubyGems versions 2.1.4 and older are vulnerable.
+
+Ruby versions 1.9.0 through 2.0.0p247 are vulnerable as they contain embedded
+versions of RubyGems.
+
+It does not appear to be possible to exploit this vulnerability by installing a
+gem for RubyGems 1.8.x or newer. Vulnerable uses of RubyGems API include
+packaging a gem (through `gem build`, Gem::Package or Gem::PackageTask),
+sending user input to Gem::Version.new, Gem::Version.correct? or use of the
+Gem::Version::VERSION_PATTERN or Gem::Version::ANCHORED_VERSION_PATTERN
+constants.
+
+Notably, users of bundler that install gems from git are vulnerable if a
+malicious author changes the gemspec to an invalid version.
+
+The vulnerability can be fixed by changing the "*" repetition to a "?"
+repetition in Gem::Version::ANCHORED_VERSION_PATTERN in
+lib/rubygems/version.rb. For RubyGems 2.1.x:
+
+ - ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
+ + ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ # :nodoc:
+
+For RubyGems 2.0.x:
+
+ - ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
+ + ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ # :nodoc:
+
+For RubyGems 1.8.x:
+
+ - ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
+ + ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ # :nodoc:
+
+
+This vulnerability was discovered by Alexander Cherepanov <cherepan@mccme.ru>
+
View
@@ -1,5 +1,14 @@
# coding: UTF-8
+=== 1.8.26 / 2013-09-24
+
+Security fixes:
+
+* RubyGems 2.1.4 and earlier are vulnerable to excessive CPU usage due to a
+ backtracking in Gem::Version validation. See CVE-2013-4363 for full details
+ including vulnerable APIs. Fixed versions include 2.1.5, 2.0.10, 1.8.27 and
+ 1.8.23.2 (for Ruby 1.9.3).
+
=== 1.8.26 / 2013-09-09
Security fixes:
View
@@ -1,6 +1,7 @@
.autotest
.document
CVE-2013-4287.txt
+CVE-2013-4363.txt
History.txt
LICENSE.txt
MIT.txt
@@ -146,7 +146,7 @@ class Gem::Version
include Comparable
VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*' # :nodoc:
- ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
+ ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/ # :nodoc:
##
# A string representation of this Version.
@@ -37,17 +37,19 @@ def test_parse
end
def test_parse_bad
- e = assert_raises ArgumentError do
- Gem::Requirement.parse nil
- end
-
- assert_equal 'Illformed requirement [nil]', e.message
+ [
+ nil,
+ '',
+ '! 1',
+ '= junk',
+ '1..2',
+ ].each do |bad|
+ e = assert_raises ArgumentError do
+ Gem::Requirement.parse bad
+ end
- e = assert_raises ArgumentError do
- Gem::Requirement.parse ""
+ assert_equal "Illformed requirement [#{bad.inspect}]", e.message
end
-
- assert_equal 'Illformed requirement [""]', e.message
end
def test_prerelease_eh
@@ -67,12 +67,18 @@ def test_initialize
end
def test_initialize_bad
- ["junk", "1.0\n2.0"].each do |bad|
- e = assert_raises ArgumentError do
+ %W[
+ junk
+ 1.0\n2.0
+ 1..2
+ 1.2\ 3.4
+ 1-2-3
+ ].each do |bad|
+ e = assert_raises ArgumentError, bad do
Gem::Version.new bad
end
- assert_equal "Malformed version number string #{bad}", e.message
+ assert_equal "Malformed version number string #{bad}", e.message, bad
end
end

0 comments on commit f63bfbc

Please sign in to comment.