JRuby 1.7.3 Released

Thursday, February 21 2013

The JRuby community is pleased to announce the release of JRuby 1.7.3

Alert Please note the primary reason for putting out 1.7.3 was to address two security issues. Everyone should upgrade to 1.7.3 (details on security issues below).

Note: This was a condensed release due to wanting to put out security fixes. If the bugs you are waiting for have not been fixed we will be fixing them for 1.7.4.

JRuby 1.7.3 is our third update release since JRuby 1.7.0. The primary goal of 1.7 point releases is to fill out any missing compatibility issues with Ruby 1.9.3. The community participation lately has been great. Keep reporting issues and sending pull requests.

Changes of note:

  • Security fix (no CVE) for DOS using entity expansion in REXML
  • Security fix (CVE-2013-0269) for unsafe object creation using JSON
  • Relicensed from CPL to EPL
  • Fixed one regression in windows java native launcher
  • A few encoding issues resolved
  • 42 issues fixed for 1.7.3

Note: These next two sections are write-ups by Aaron Patterson on the security issues. JRuby 1.7.3 fixes both of these issues. You only need to be aware of workarounds if it is impossible for you to update JRuby to version 1.7.3.

Rexml DOS Fix

Impact

When reading text nodes from an XML document, the REXML parser can be coerced in to allocating extremely large string objects which can consume all of the memory on a machine, causing a denial of service.

Impacted code will look something like this:

document = REXML::Document.new some_xml_doc
document.root.text

When the text method is called, entities will be expanded. An attacker can send a relatively small XML document that, when the entities are resolved, will consume extreme amounts of memory on the target system.

Note that this attack is similar to, but different from the Billion Laughs attack. This is also related to CVE-2013-1664.

All users running an affected release should either upgrade or use one of the work arounds immediately.

Workarounds

If you cannot upgrade Ruby, use this monkey patch as a workaround:

class REXML::Document
  @@entity_expansion_text_limit = 10_240

  def self.entity_expansion_text_limit=( val )
    @@entity_expansion_text_limit = val
  end

  def self.entity_expansion_text_limit
    @@entity_expansion_text_limit
  end
end

class REXML::Text
  def self.unnormalize(string, doctype=nil, filter=nil, illegal=nil)
    sum = 0
    string.gsub( /\r\n?/, "\n" ).gsub( REFERENCE ) {
      s = self.expand($&, doctype, filter)
      if sum + s.bytesize > REXML::Document.entity_expansion_text_limit
        raise "entity expansion has grown too large"
      else
        sum += s.bytesize
      end
      s
    }
  end

  def self.expand(ref, doctype, filter)
    if ref[1] == ?#
      if ref[2] == ?x
        [ref[3...-1].to_i(16)].pack('U*')
      else
        [ref[2...-1].to_i].pack('U*')
      end
    elsif ref == '&'
      '&'
    elsif filter and filter.include?( ref[1...-1] )
      ref
    elsif doctype
      doctype.entity( ref[1...-1] ) or ref
    else
      entity_value = DocType::DEFAULT_ENTITIES[ ref[1...-1] ]
      entity_value ? entity_value.value : ref
    end
  end
end

This monkey patch will limit the size of the entity substitutions to 10k per node. REXML already defaults to only allow 10000 entity substitutions per document, so the maximum amount of text that can be generated by entity substitution will be around 98 megabytes.

JSON Security Fix CVE-2013-0269

Impact

When parsing certain JSON documents, the JSON gem can be coerced in to creating Ruby symbols in a target system. Since Ruby symbols are not garbage collected, this can result in a denial of service attack.

The same technique can be used to create objects in a target system that act like internal objects. These “act alike” objects can be used to bypass certain security mechanisms and can be used as a spring board for SQL injection attacks in Ruby on Rails.

Impacted code looks like this:

JSON.parse(user_input)

Where the user_input variable will have a JSON document like this:

{"json_class":"foo"}

The JSON gem will attempt to look up the constant “foo”. Looking up this constant will create a symbol.

In JSON version 1.7.x, objects with arbitrary attributes can be created using JSON documents like this:

{"json_class":"JSON::GenericObject","foo":"bar"}

This document will result in an instance of JSON::GenericObject, with the attribute “foo” that has the value “bar”. Instantiating these objects will result in arbitrary symbol creation and in some cases can be used to bypass security measures.

PLEASE NOTE: this behavior does not change when using JSON.load. JSON.load should never be given input from unknown sources. If you are processing JSON from an unknown source, always use JSON.parse.

All users running an affected release should either upgrade or use one of the work arounds immediately.

Workarounds

For users that cannot upgrade, please use the attached patches. If you cannot use the attached patches, change your code from this:

JSON.parse(json)

To this:

JSON.parse(json, :create_additions => false)

If you cannot change the usage of JSON.parse (for example you’re using a gem which depends on JSON.parse like multi_json), then apply this monkey patch:

module JSON
  class << self
    alias :old_parse :parse
    def parse(json, args = {})
      args[:create_additions] = false
      old_parse(json, args)
    end
  end
end

Jira Issues resolved for 1.7.3

  • JRUBY-7058 - NPE in BiVariableMap.getLocalVarNames() after clear()
  • JRUBY-6887 - Thread.current.object_id inside an Enumerator is different from outside it
  • JRUBY-7048 - Kernel#gsub is not available when -p/-n command line option specified.
  • JRUBY-7068 - StringIO.open should accept any number of arguments
  • JRUBY-7069 - Dir.home(nil) should be my home
  • JRUBY-7079 - Uninitialized constant NameError should store a symbol and not a string
  • JRUBY-6793 - Update bouncycastle jars to the latest version. (1.47)
  • JRUBY-7081 - Thread.current does not remain consistent between Fibers
  • JRUBY-7091 - Infinity should not be roundable :)
  • JRUBY-7035 - Rails 4 master doesn't start on JRuby 1.7.1 (OpenSSL::PKCS5)
  • JRUBY-7001 - maven jruby-rake-plugin classpath goal fails on windows
  • JRUBY-7084 - Interaction between oh-my-zsh configuration and jruby shell script

Github Issues resolved for 1.7.3

  • #537 - Add the complete text of the Eclipse Public License
  • #536 - Fix occasionally failing spec.
  • #534 - Fix Enumerable#find_each block arity
  • #533 - Default indy off for early IBM Java 7 releases #477
  • #532 - Current head switches on +indy before 1.7update14
  • #529 - Combination of Enumerable#each_slice and Array#transpose raises TypeError
  • #528 - fix samples/mvm.rb
  • #526 - Move to EPL from CPL
  • #525 - Unexpected behaviour of `Enumerator#find_index` with block (1.9 mode and HEAD)
  • #519 - nailgun missing in src package
  • #518 - Fix typos in "1.9/io/console.rb"
  • #517 - Rational/Float/Fixnum/Bignum `.to_s.encoding` is US-ASCII
  • #516 - krypt is not 1.8-compatible
  • #512 - Update json to 1.7.6
  • #511 - tty issue with drip
  • #508 - added Junit test to help fixing bug #7058
  • #506 - throw stringifies the name
  • #504 - Infinite loop (or performance issue) writing using MultiByteEncoding
  • #494 - FFI::MemoryPointer#free may cause JVM crashes
  • #492 - Add missing throw to default_internal=.
  • #485 - Resolve #482 Array#zip with infinite enum results in OOM
  • #482 - Combination of Array#zip and Array#cycle result in OOM
  • #479 - Fix write loss on concurrent ivar table growth
  • #477 - IBM J9 VM should also have INVOKEDYNAMIC_DEFAULT = false
  • #470 - Bignum#div raise ZeroDivisionError if the argument is Float zero
  • #466 - Bunch of fixes for IO.copy_stream
  • #465 - Add const_get to java package Fixes #435
  • #464 - [rfc] Support unmarshaling hashes created in MRI 1.9.1 with US-ASCII strings
  • #457 - Accept Encoding object for Encoding.compatible?
  • #435 - support for const_get() in java_package_module_template