[DRE-commits] [rails] 01/02: Several security updates

Antonio Terceiro terceiro at moszumanska.debian.org
Thu Jan 28 19:04:52 UTC 2016


This is an automated email from the git hooks/post-receive script.

terceiro pushed a commit to branch debian/jessie
in repository rails.

commit 5cb92f0df4467e6589c25ec6bfe5a745b51ee7c1
Author: Antonio Terceiro <terceiro at debian.org>
Date:   Thu Jan 28 11:16:13 2016 -0200

    Several security updates
---
 debian/changelog                   |  17 +++
 debian/patches/CVE-2015-3226.patch |  48 +++++++
 debian/patches/CVE-2015-3227.patch | 113 +++++++++++++++
 debian/patches/CVE-2015-7576.patch |  77 ++++++++++
 debian/patches/CVE-2015-7577.patch |  86 +++++++++++
 debian/patches/CVE-2015-7581.patch |  52 +++++++
 debian/patches/CVE-2016-0751.patch |  76 ++++++++++
 debian/patches/CVE-2016-0752.patch | 285 +++++++++++++++++++++++++++++++++++++
 debian/patches/CVE-2016-0753.patch |  83 +++++++++++
 debian/patches/series              |   8 ++
 10 files changed, 845 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index ff85cf3..7707d19 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,20 @@
+rails (2:4.1.8-1+deb8u1) jessie-security; urgency=high
+
+  * Security updates:
+    - [CVE-2015-3227] Possible Denial of Service attack in Active Support
+    - [CVE-2015-3226] XSS Vulnerability in ActiveSupport::JSON.encode
+    - [CVE-2015-7576] Timing attack vulnerability in basic authentication in
+                      Action Controller.
+    - [CVE-2016-0751] Possible Object Leak and Denial of Service attack in
+                      Action Pack
+    - [CVE-2015-7577] Nested attributes rejection proc bypass in Active Record.
+    - [CVE-2016-0752] Possible Information Leak Vulnerability in Action View
+    - [CVE-2016-0753] Possible Input Validation Circumvention in Active Model
+    - [CVE-2015-7581] Object leak vulnerability for wildcard controller routes
+                      in Action Pack
+
+ -- Antonio Terceiro <terceiro at debian.org>  Thu, 28 Jan 2016 11:12:33 -0200
+
 rails (2:4.1.8-1) unstable; urgency=medium
 
   * New upstream release
diff --git a/debian/patches/CVE-2015-3226.patch b/debian/patches/CVE-2015-3226.patch
new file mode 100644
index 0000000..9f5347d
--- /dev/null
+++ b/debian/patches/CVE-2015-3226.patch
@@ -0,0 +1,48 @@
+From bfbf16749a754ab1fd58274a951d3a013182a635 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafael=20Mendon=C3=A7a=20Fran=C3=A7a?=
+ <rafaelmfranca at gmail.com>
+Date: Mon, 15 Jun 2015 15:23:01 -0300
+Subject: [PATCH] Escape HTML entities in JSON keys
+
+Fixes CVE-2015-3226
+---
+ activesupport/lib/active_support/json/encoding.rb | 4 ++++
+ activesupport/test/json/encoding_test.rb          | 7 +++++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
+index f29d422..d0f67b1 100644
+--- a/activesupport/lib/active_support/json/encoding.rb
++++ b/activesupport/lib/active_support/json/encoding.rb
+@@ -58,6 +58,10 @@ module ActiveSupport
+                 super.gsub ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS
+               end
+             end
++
++            def to_s
++              self
++            end
+           end
+ 
+           # Mark these as private so we don't leak encoding-specific constructs
+diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
+index c4283ee..b75c67c 100644
+--- a/activesupport/test/json/encoding_test.rb
++++ b/activesupport/test/json/encoding_test.rb
+@@ -143,6 +143,13 @@ class TestJSONEncoding < ActiveSupport::TestCase
+     assert_equal %({\"a\":\"b\",\"c\":\"d\"}), sorted_json(ActiveSupport::JSON.encode(:a => :b, :c => :d))
+   end
+ 
++  def test_hash_keys_encoding
++    ActiveSupport.escape_html_entities_in_json = true
++    assert_equal "{\"\\u003c\\u003e\":\"\\u003c\\u003e\"}", ActiveSupport::JSON.encode("<>" => "<>")
++  ensure
++    ActiveSupport.escape_html_entities_in_json = false
++  end
++
+   def test_utf8_string_encoded_properly
+     result = ActiveSupport::JSON.encode('€2.99')
+     assert_equal '"€2.99"', result
+-- 
+2.4.0
+
diff --git a/debian/patches/CVE-2015-3227.patch b/debian/patches/CVE-2015-3227.patch
new file mode 100644
index 0000000..d8a4084
--- /dev/null
+++ b/debian/patches/CVE-2015-3227.patch
@@ -0,0 +1,113 @@
+From eb4f1d6a02e9557b97cdbed76157dc5a625cdb82 Mon Sep 17 00:00:00 2001
+From: Aaron Patterson <aaron.patterson at gmail.com>
+Date: Tue, 9 Jun 2015 11:24:25 -0700
+Subject: [PATCH] enforce a depth limit on XML documents
+
+XML documents that are too deep can cause an stack overflow, which in
+turn will cause a potential DoS attack.
+
+CVE-2015-3227
+---
+ activesupport/lib/active_support/xml_mini.rb       |  3 +++
+ activesupport/lib/active_support/xml_mini/jdom.rb  | 11 ++++++-----
+ activesupport/lib/active_support/xml_mini/rexml.rb | 11 ++++++-----
+ 3 files changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
+index 009ee4d..df7b081 100644
+--- a/activesupport/lib/active_support/xml_mini.rb
++++ b/activesupport/lib/active_support/xml_mini.rb
+@@ -78,6 +78,9 @@ module ActiveSupport
+       )
+     end
+ 
++    attr_accessor :depth
++    self.depth = 100
++
+     delegate :parse, :to => :backend
+ 
+     def backend
+diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb
+index 27c64c4..cdc5490 100644
+--- a/activesupport/lib/active_support/xml_mini/jdom.rb
++++ b/activesupport/lib/active_support/xml_mini/jdom.rb
+@@ -46,7 +46,7 @@ module ActiveSupport
+         xml_string_reader = StringReader.new(data)
+         xml_input_source = InputSource.new(xml_string_reader)
+         doc = @dbf.new_document_builder.parse(xml_input_source)
+-        merge_element!({CONTENT_KEY => ''}, doc.document_element)
++        merge_element!({CONTENT_KEY => ''}, doc.document_element, XmlMini.depth)
+       end
+     end
+ 
+@@ -58,9 +58,10 @@ module ActiveSupport
+     #   Hash to merge the converted element into.
+     # element::
+     #   XML element to merge into hash
+-    def merge_element!(hash, element)
++    def merge_element!(hash, element, depth)
++      raise 'Document too deep!' if depth == 0
+       delete_empty(hash)
+-      merge!(hash, element.tag_name, collapse(element))
++      merge!(hash, element.tag_name, collapse(element, depth))
+     end
+ 
+     def delete_empty(hash)
+@@ -71,14 +72,14 @@ module ActiveSupport
+     #
+     # element::
+     #   The document element to be collapsed.
+-    def collapse(element)
++    def collapse(element, depth)
+       hash = get_attributes(element)
+ 
+       child_nodes = element.child_nodes
+       if child_nodes.length > 0
+         (0...child_nodes.length).each do |i|
+           child = child_nodes.item(i)
+-          merge_element!(hash, child) unless child.node_type == Node.TEXT_NODE
++          merge_element!(hash, child, depth - 1) unless child.node_type == Node.TEXT_NODE
+         end
+         merge_texts!(hash, element) unless empty_content?(element)
+         hash
+diff --git a/activesupport/lib/active_support/xml_mini/rexml.rb b/activesupport/lib/active_support/xml_mini/rexml.rb
+index 5c7c78b..924ed72 100644
+--- a/activesupport/lib/active_support/xml_mini/rexml.rb
++++ b/activesupport/lib/active_support/xml_mini/rexml.rb
+@@ -29,7 +29,7 @@ module ActiveSupport
+         doc = REXML::Document.new(data)
+ 
+         if doc.root
+-          merge_element!({}, doc.root)
++          merge_element!({}, doc.root, XmlMini.depth)
+         else
+           raise REXML::ParseException,
+             "The document #{doc.to_s.inspect} does not have a valid root"
+@@ -44,19 +44,20 @@ module ActiveSupport
+       #   Hash to merge the converted element into.
+       # element::
+       #   XML element to merge into hash
+-      def merge_element!(hash, element)
+-        merge!(hash, element.name, collapse(element))
++      def merge_element!(hash, element, depth)
++        raise REXML::ParseException, "The document is too deep" if depth == 0
++        merge!(hash, element.name, collapse(element, depth))
+       end
+ 
+       # Actually converts an XML document element into a data structure.
+       #
+       # element::
+       #   The document element to be collapsed.
+-      def collapse(element)
++      def collapse(element, depth)
+         hash = get_attributes(element)
+ 
+         if element.has_elements?
+-          element.each_element {|child| merge_element!(hash, child) }
++          element.each_element {|child| merge_element!(hash, child, depth - 1) }
+           merge_texts!(hash, element) unless empty_content?(element)
+           hash
+         else
+-- 
+2.2.1
+
diff --git a/debian/patches/CVE-2015-7576.patch b/debian/patches/CVE-2015-7576.patch
new file mode 100644
index 0000000..d388b0e
--- /dev/null
+++ b/debian/patches/CVE-2015-7576.patch
@@ -0,0 +1,77 @@
+From 0de876c53fe9355f1e9a73e923519f2a2241f527 Mon Sep 17 00:00:00 2001
+From: Aaron Patterson <aaron.patterson at gmail.com>
+Date: Thu, 29 Oct 2015 10:42:44 -0700
+Subject: [PATCH] use secure string comparisons for basic auth username /
+ password
+
+this will avoid timing attacks against applications that use basic auth.
+
+Conflicts:
+	activesupport/lib/active_support/security_utils.rb
+
+CVE-2015-7576
+---
+ .../action_controller/metal/http_authentication.rb |  7 +++++-
+ activesupport/lib/active_support/security_utils.rb | 27 ++++++++++++++++++++++
+ 2 files changed, 33 insertions(+), 1 deletion(-)
+ create mode 100644 activesupport/lib/active_support/security_utils.rb
+
+diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
+index 167df2f..db93e20 100644
+--- a/actionpack/lib/action_controller/metal/http_authentication.rb
++++ b/actionpack/lib/action_controller/metal/http_authentication.rb
+@@ -1,4 +1,5 @@
+ require 'base64'
++require 'active_support/security_utils'
+ 
+ module ActionController
+   # Makes it dead easy to do HTTP Basic, Digest and Token authentication.
+@@ -70,7 +71,11 @@ module ActionController
+           def http_basic_authenticate_with(options = {})
+             before_action(options.except(:name, :password, :realm)) do
+               authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
+-                name == options[:name] && password == options[:password]
++                # This comparison uses & so that it doesn't short circuit and
++                # uses `variable_size_secure_compare` so that length information
++                # isn't leaked.
++                ActiveSupport::SecurityUtils.variable_size_secure_compare(name, options[:name]) &
++                  ActiveSupport::SecurityUtils.variable_size_secure_compare(password, options[:password])
+               end
+             end
+           end
+diff --git a/activesupport/lib/active_support/security_utils.rb b/activesupport/lib/active_support/security_utils.rb
+new file mode 100644
+index 0000000..bb22125
+--- /dev/null
++++ b/activesupport/lib/active_support/security_utils.rb
+@@ -0,0 +1,27 @@
++require 'digest'
++
++module ActiveSupport
++  module SecurityUtils
++    # Constant time string comparison.
++    #
++    # The values compared should be of fixed length, such as strings
++    # that have already been processed by HMAC. This should not be used
++    # on variable length plaintext strings because it could leak length info
++    # via timing attacks.
++    def secure_compare(a, b)
++      return false unless a.bytesize == b.bytesize
++
++      l = a.unpack "C#{a.bytesize}"
++
++      res = 0
++      b.each_byte { |byte| res |= byte ^ l.shift }
++      res == 0
++    end
++    module_function :secure_compare
++
++    def variable_size_secure_compare(a, b) # :nodoc:
++      secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b))
++    end
++    module_function :variable_size_secure_compare
++  end
++end
+-- 
+2.2.1
+
diff --git a/debian/patches/CVE-2015-7577.patch b/debian/patches/CVE-2015-7577.patch
new file mode 100644
index 0000000..cc667c1
--- /dev/null
+++ b/debian/patches/CVE-2015-7577.patch
@@ -0,0 +1,86 @@
+From 5dc869dc73bcbe0b3dd415f257cf175015c4d014 Mon Sep 17 00:00:00 2001
+From: Andrew White <andyw at pixeltrix.co.uk>
+Date: Fri, 27 Nov 2015 13:46:46 +0000
+Subject: [PATCH] Don't short-circuit reject_if proc
+
+When updating an associated record via nested attribute hashes the
+reject_if proc could be bypassed if the _destroy flag was set in the
+attribute hash and allow_destroy was set to false.
+
+The fix is to only short-circuit if the _destroy flag is set and the
+option allow_destroy is set to true. It also fixes an issue where
+a new record wasn't created if _destroy was set and the option
+allow_destroy was set to false.
+
+CVE-2015-7577
+---
+ activerecord/lib/active_record/nested_attributes.rb | 14 ++++++++++++--
+ activerecord/test/cases/nested_attributes_test.rb   | 13 +++++++++++++
+ 2 files changed, 25 insertions(+), 2 deletions(-)
+
+diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
+index 6df01b7..03a4009 100644
+--- a/activerecord/lib/active_record/nested_attributes.rb
++++ b/activerecord/lib/active_record/nested_attributes.rb
+@@ -523,7 +523,7 @@ module ActiveRecord
+     # has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
+     # association and evaluates to +true+.
+     def reject_new_record?(association_name, attributes)
+-      has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
++      will_be_destroyed?(association_name, attributes) || call_reject_if(association_name, attributes)
+     end
+ 
+     # Determines if a record with the particular +attributes+ should be
+@@ -532,7 +532,8 @@ module ActiveRecord
+     #
+     # Returns false if there is a +destroy_flag+ on the attributes.
+     def call_reject_if(association_name, attributes)
+-      return false if has_destroy_flag?(attributes)
++      return false if will_be_destroyed?(association_name, attributes)
++
+       case callback = self.nested_attributes_options[association_name][:reject_if]
+       when Symbol
+         method(callback).arity == 0 ? send(callback) : send(callback, attributes)
+@@ -541,6 +542,15 @@ module ActiveRecord
+       end
+     end
+ 
++    # Only take into account the destroy flag if <tt>:allow_destroy</tt> is true
++    def will_be_destroyed?(association_name, attributes)
++      allow_destroy?(association_name) && has_destroy_flag?(attributes)
++    end
++
++    def allow_destroy?(association_name)
++      self.nested_attributes_options[association_name][:allow_destroy]
++    end
++
+     def raise_nested_attributes_record_not_found!(association_name, record_id)
+       raise RecordNotFound, "Couldn't find #{self.class._reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
+     end
+diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
+index c87a837..e421600 100644
+--- a/activerecord/test/cases/nested_attributes_test.rb
++++ b/activerecord/test/cases/nested_attributes_test.rb
+@@ -161,6 +161,19 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
+     assert man.reload.interests.empty?
+   end
+ 
++  def test_reject_if_is_not_short_circuited_if_allow_destroy_is_false
++    Pirate.accepts_nested_attributes_for :ship, reject_if: ->(a) { a[:name] == "The Golden Hind" }, allow_destroy: false
++
++    pirate = Pirate.create!(catchphrase: "Stop wastin' me time", ship_attributes: { name: "White Pearl", _destroy: "1" })
++    assert_equal "White Pearl", pirate.reload.ship.name
++
++    pirate.update!(ship_attributes: { id: pirate.ship.id, name: "The Golden Hind", _destroy: "1" })
++    assert_equal "White Pearl", pirate.reload.ship.name
++
++    pirate.update!(ship_attributes: { id: pirate.ship.id, name: "Black Pearl", _destroy: "1" })
++    assert_equal "Black Pearl", pirate.reload.ship.name
++  end
++
+   def test_has_many_association_updating_a_single_record
+     Man.accepts_nested_attributes_for(:interests)
+     man = Man.create(name: 'John')
+-- 
+2.4.9 (Apple Git-60)
+
diff --git a/debian/patches/CVE-2015-7581.patch b/debian/patches/CVE-2015-7581.patch
new file mode 100644
index 0000000..096a6a5
--- /dev/null
+++ b/debian/patches/CVE-2015-7581.patch
@@ -0,0 +1,52 @@
+From fb790341d0ea25ad91116c283d49a2c83a8ea299 Mon Sep 17 00:00:00 2001
+From: eileencodes <eileencodes at gmail.com>
+Date: Fri, 21 Aug 2015 11:26:19 -0400
+Subject: [PATCH] Remove unnecessary caching
+
+`ActiveSupport::Dependencies.constantize(const_name)` calls
+`Reference.new` which is defined as
+`ActiveSupport::Dependencies.constantize(const_name)` meaning this call
+is already cached and we're doing caching that isn't necessary.
+
+Conflicts:
+	actionpack/lib/action_dispatch/routing/route_set.rb
+
+Conflicts:
+	actionpack/lib/action_dispatch/routing/route_set.rb
+
+CVE-2015-7581
+---
+ actionpack/lib/action_dispatch/routing/route_set.rb | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
+index 51dd607..5f727fd 100644
+--- a/actionpack/lib/action_dispatch/routing/route_set.rb
++++ b/actionpack/lib/action_dispatch/routing/route_set.rb
+@@ -1,6 +1,5 @@
+ require 'action_dispatch/journey'
+ require 'forwardable'
+-require 'thread_safe'
+ require 'active_support/concern'
+ require 'active_support/core_ext/object/to_query'
+ require 'active_support/core_ext/hash/slice'
+@@ -24,7 +23,6 @@ module ActionDispatch
+         def initialize(options={})
+           @defaults = options[:defaults]
+           @glob_param = options.delete(:glob)
+-          @controller_class_names = ThreadSafe::Cache.new
+         end
+ 
+         def call(env)
+@@ -74,7 +72,7 @@ module ActionDispatch
+       private
+ 
+         def controller_reference(controller_param)
+-          const_name = @controller_class_names[controller_param] ||= "#{controller_param.camelize}Controller"
++          const_name = "#{controller_param.camelize}Controller"
+           ActiveSupport::Dependencies.constantize(const_name)
+         end
+ 
+-- 
+2.2.1
+
diff --git a/debian/patches/CVE-2016-0751.patch b/debian/patches/CVE-2016-0751.patch
new file mode 100644
index 0000000..725f605
--- /dev/null
+++ b/debian/patches/CVE-2016-0751.patch
@@ -0,0 +1,76 @@
+From 5756321cd9e3ca12cb2b8402704c6680b4d7ca2a Mon Sep 17 00:00:00 2001
+From: Aaron Patterson <aaron.patterson at gmail.com>
+Date: Mon, 11 Jan 2016 14:36:49 -0800
+Subject: [PATCH] stop caching mime types globally
+
+Unknown mime types should not be cached globally.  This global cache
+leads to a memory leak and a denial of service vulnerability.
+
+CVE-2016-0751
+---
+ actionpack/lib/action_dispatch/http/mime_type.rb | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
+index 9450be8..fc986f9 100644
+--- a/actionpack/lib/action_dispatch/http/mime_type.rb
++++ b/actionpack/lib/action_dispatch/http/mime_type.rb
+@@ -23,7 +23,7 @@ module Mime
+ 
+   SET              = Mimes.new
+   EXTENSION_LOOKUP = {}
+-  LOOKUP           = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
++  LOOKUP           = {}
+ 
+   class << self
+     def [](type)
+@@ -146,7 +146,7 @@ module Mime
+       end
+ 
+       def lookup(string)
+-        LOOKUP[string]
++        LOOKUP[string] || Type.new(string)
+       end
+ 
+       def lookup_by_extension(extension)
+@@ -225,9 +225,12 @@ module Mime
+       end
+     end
+ 
++    attr_reader :hash
++
+     def initialize(string, symbol = nil, synonyms = [])
+       @symbol, @synonyms = symbol, synonyms
+       @string = string
++      @hash = [@string, @synonyms, @symbol].hash
+     end
+ 
+     def to_s
+@@ -261,6 +264,13 @@ module Mime
+       end
+     end
+ 
++    def eql?(other)
++      super || (self.class == other.class &&
++                @string    == other.string &&
++                @synonyms  == other.synonyms &&
++                @symbol    == other.symbol)
++    end
++
+     def =~(mime_type)
+       return false if mime_type.blank?
+       regexp = Regexp.new(Regexp.quote(mime_type.to_s))
+@@ -274,6 +284,10 @@ module Mime
+     end
+ 
+ 
++    protected
++
++    attr_reader :string, :synonyms
++
+     private
+ 
+     def to_ary; end
+-- 
+2.2.1
+
diff --git a/debian/patches/CVE-2016-0752.patch b/debian/patches/CVE-2016-0752.patch
new file mode 100644
index 0000000..96a8804
--- /dev/null
+++ b/debian/patches/CVE-2016-0752.patch
@@ -0,0 +1,285 @@
+From 5c656a271a890cca4b3d438cc1fc76ff98011cbe Mon Sep 17 00:00:00 2001
+From: Aaron Patterson <aaron.patterson at gmail.com>
+Date: Wed, 20 Jan 2016 10:39:19 -0800
+Subject: [PATCH] allow :file to be outside rails root, but anything else must
+ be inside the rails view directory
+
+Conflicts:
+	actionpack/test/controller/render_test.rb
+	actionview/lib/action_view/template/resolver.rb
+
+CVE-2016-0752
+---
+ actionpack/lib/abstract_controller/rendering.rb    |  8 +++++-
+ actionpack/test/controller/render_test.rb          | 31 ++++++++++++++++++++++
+ actionview/lib/action_view/lookup_context.rb       |  4 +++
+ actionview/lib/action_view/path_set.rb             | 26 +++++++++++++-----
+ .../lib/action_view/renderer/abstract_renderer.rb  |  2 +-
+ .../lib/action_view/renderer/template_renderer.rb  |  2 +-
+ actionview/lib/action_view/template/resolver.rb    | 25 ++++++++++++++---
+ actionview/lib/action_view/testing/resolvers.rb    |  4 +--
+ actionview/test/template/render_test.rb            |  7 +++++
+ 9 files changed, 93 insertions(+), 16 deletions(-)
+
+diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
+index 9d10140..e80d97f 100644
+--- a/actionpack/lib/abstract_controller/rendering.rb
++++ b/actionpack/lib/abstract_controller/rendering.rb
+@@ -77,7 +77,13 @@ module AbstractController
+     # render "foo/bar" to render :file => "foo/bar".
+     # :api: plugin
+     def _normalize_args(action=nil, options={})
+-      if action.is_a? Hash
++      case action
++      when ActionController::Parameters
++        unless action.permitted?
++          raise ArgumentError, "render parameters are not permitted"
++        end
++        action
++      when Hash
+         action
+       else
+         options
+diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
+index 26806fb..17a019e 100644
+--- a/actionpack/test/controller/render_test.rb
++++ b/actionpack/test/controller/render_test.rb
+@@ -52,6 +52,16 @@ class TestController < ActionController::Base
+     end
+   end
+ 
++  def dynamic_render
++    render params[:id] # => String, AC:Params
++  end
++
++  def dynamic_render_with_file
++    # This is extremely bad, but should be possible to do.
++    file = params[:id] # => String, AC:Params
++    render file: file
++  end
++
+   def conditional_hello_with_public_header
+     if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123], :public => true)
+       render :action => 'hello_world'
+@@ -251,6 +261,27 @@ end
+ class ExpiresInRenderTest < ActionController::TestCase
+   tests TestController
+ 
++  def test_dynamic_render_with_file
++    # This is extremely bad, but should be possible to do.
++    assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
++    response = get :dynamic_render_with_file, { id: '../\\../test/abstract_unit.rb' }
++    assert_equal File.read(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')),
++      response.body
++  end
++
++  def test_dynamic_render
++    assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
++    assert_raises ActionView::MissingTemplate do
++      get :dynamic_render, { id: '../\\../test/abstract_unit.rb' }
++    end
++  end
++
++  def test_dynamic_render_file_hash
++    assert_raises ArgumentError do
++      get :dynamic_render, { id: { file: '../\\../test/abstract_unit.rb' } }
++    end
++  end
++
+   def test_expires_in_header
+     get :conditional_hello_with_expires_in
+     assert_equal "max-age=60, private", @response.headers["Cache-Control"]
+diff --git a/actionview/lib/action_view/lookup_context.rb b/actionview/lib/action_view/lookup_context.rb
+index 855fed0..93ef701 100644
+--- a/actionview/lib/action_view/lookup_context.rb
++++ b/actionview/lib/action_view/lookup_context.rb
+@@ -125,6 +125,10 @@ module ActionView
+       end
+       alias :find_template :find
+ 
++      def find_file(name, prefixes = [], partial = false, keys = [], options = {})
++        @view_paths.find_file(*args_for_lookup(name, prefixes, partial, keys, options))
++      end
++
+       def find_all(name, prefixes = [], partial = false, keys = [], options = {})
+         @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
+       end
+diff --git a/actionview/lib/action_view/path_set.rb b/actionview/lib/action_view/path_set.rb
+index 91ee2ea..8d21913 100644
+--- a/actionview/lib/action_view/path_set.rb
++++ b/actionview/lib/action_view/path_set.rb
+@@ -46,23 +46,35 @@ module ActionView #:nodoc:
+       find_all(*args).first || raise(MissingTemplate.new(self, *args))
+     end
+ 
++    def find_file(path, prefixes = [], *args)
++      _find_all(path, prefixes, args, true).first || raise(MissingTemplate.new(self, path, prefixes, *args))
++    end
++
+     def find_all(path, prefixes = [], *args)
++      _find_all path, prefixes, args, false
++    end
++
++    def exists?(path, prefixes, *args)
++      find_all(path, prefixes, *args).any?
++    end
++
++    private
++
++    def _find_all(path, prefixes, args, outside_app)
+       prefixes = [prefixes] if String === prefixes
+       prefixes.each do |prefix|
+         paths.each do |resolver|
+-          templates = resolver.find_all(path, prefix, *args)
++          if outside_app
++            templates = resolver.find_all_anywhere(path, prefix, *args)
++          else
++            templates = resolver.find_all(path, prefix, *args)
++          end
+           return templates unless templates.empty?
+         end
+       end
+       []
+     end
+ 
+-    def exists?(path, prefixes, *args)
+-      find_all(path, prefixes, *args).any?
+-    end
+-
+-    private
+-
+     def typecast(paths)
+       paths.map do |path|
+         case path
+diff --git a/actionview/lib/action_view/renderer/abstract_renderer.rb b/actionview/lib/action_view/renderer/abstract_renderer.rb
+index 73c19a0..8457008 100644
+--- a/actionview/lib/action_view/renderer/abstract_renderer.rb
++++ b/actionview/lib/action_view/renderer/abstract_renderer.rb
+@@ -15,7 +15,7 @@ module ActionView
+   # that new object is called in turn. This abstracts the setup and rendering
+   # into a separate classes for partials and templates.
+   class AbstractRenderer #:nodoc:
+-    delegate :find_template, :template_exists?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context
++    delegate :find_template, :find_file, :template_exists?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context
+ 
+     def initialize(lookup_context)
+       @lookup_context = lookup_context
+diff --git a/actionview/lib/action_view/renderer/template_renderer.rb b/actionview/lib/action_view/renderer/template_renderer.rb
+index be17097..66b611d 100644
+--- a/actionview/lib/action_view/renderer/template_renderer.rb
++++ b/actionview/lib/action_view/renderer/template_renderer.rb
+@@ -30,7 +30,7 @@ module ActionView
+       elsif options.key?(:html)
+         Template::HTML.new(options[:html], formats.first)
+       elsif options.key?(:file)
+-        with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
++        with_fallbacks { find_file(options[:file], nil, false, keys, @details) }
+       elsif options.key?(:inline)
+         handler = Template.handler_for_extension(options[:type] || "erb")
+         Template.new(options[:inline], "inline template", handler, :locals => keys)
+diff --git a/actionview/lib/action_view/template/resolver.rb b/actionview/lib/action_view/template/resolver.rb
+index f1bb47a..8d8a37e 100644
+--- a/actionview/lib/action_view/template/resolver.rb
++++ b/actionview/lib/action_view/template/resolver.rb
+@@ -112,7 +112,13 @@ module ActionView
+     # Normalizes the arguments and passes it on to find_templates.
+     def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[])
+       cached(key, [name, prefix, partial], details, locals) do
+-        find_templates(name, prefix, partial, details)
++        find_templates(name, prefix, partial, details, false)
++      end
++    end
++
++    def find_all_anywhere(name, prefix, partial=false, details={}, key=nil, locals=[])
++      cached(key, [name, prefix, partial], details, locals) do
++        find_templates(name, prefix, partial, details, true)
+       end
+     end
+ 
+@@ -173,15 +179,16 @@ module ActionView
+ 
+     private
+ 
+-    def find_templates(name, prefix, partial, details)
++    def find_templates(name, prefix, partial, details, outside_app_allowed = false)
+       path = Path.build(name, prefix, partial)
+-      query(path, details, details[:formats])
++      query(path, details, details[:formats], outside_app_allowed)
+     end
+ 
+-    def query(path, details, formats)
++    def query(path, details, formats, outside_app_allowed)
+       query = build_query(path, details)
+ 
+       template_paths = find_template_paths query
++      template_paths = reject_files_external_to_app(template_paths) unless outside_app_allowed
+ 
+       template_paths.map { |template|
+         handler, format, variant = extract_handler_and_format_and_variant(template, formats)
+@@ -196,6 +203,10 @@ module ActionView
+       }
+     end
+ 
++    def reject_files_external_to_app(files)
++      files.reject { |filename| !inside_path?(@path, filename) }
++    end
++
+     if RUBY_VERSION >= '2.2.0'
+       def find_template_paths(query)
+         Dir[query].reject { |filename|
+@@ -216,6 +227,12 @@ module ActionView
+       end
+     end
+ 
++    def inside_path?(path, filename)
++      filename = File.expand_path(filename)
++      path = File.join(path, '')
++      filename.start_with?(path)
++    end
++
+     # Helper for building query glob string based on resolver's pattern.
+     def build_query(path, details)
+       query = @pattern.dup
+diff --git a/actionview/lib/action_view/testing/resolvers.rb b/actionview/lib/action_view/testing/resolvers.rb
+index dfb7d46..e88f425 100644
+--- a/actionview/lib/action_view/testing/resolvers.rb
++++ b/actionview/lib/action_view/testing/resolvers.rb
+@@ -19,7 +19,7 @@ module ActionView #:nodoc:
+ 
+   private
+ 
+-    def query(path, exts, formats)
++    def query(path, exts, formats, _)
+       query = ""
+       EXTENSIONS.each_key do |ext|
+         query << '(' << exts[ext].map {|e| e && Regexp.escape(".#{e}") }.join('|') << '|)'
+@@ -44,7 +44,7 @@ module ActionView #:nodoc:
+   end
+ 
+   class NullResolver < PathResolver
+-    def query(path, exts, formats)
++    def query(path, exts, formats, _)
+       handler, format, variant = extract_handler_and_format_and_variant(path, formats)
+       [ActionView::Template.new("Template generated by Null Resolver", path, handler, :virtual_path => path, :format => format, :variant => variant)]
+     end
+diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb
+index 1316f85..caf6d13 100644
+--- a/actionview/test/template/render_test.rb
++++ b/actionview/test/template/render_test.rb
+@@ -142,6 +142,13 @@ module RenderTestCases
+     assert_equal "only partial", @view.render("test/partial_only")
+   end
+ 
++  def test_render_outside_path
++    assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
++    assert_raises ActionView::MissingTemplate do
++      @view.render(:template => "../\\../test/abstract_unit.rb")
++    end
++  end
++
+   def test_render_partial
+     assert_equal "only partial", @view.render(:partial => "test/partial_only")
+   end
+-- 
+2.2.1
+
diff --git a/debian/patches/CVE-2016-0753.patch b/debian/patches/CVE-2016-0753.patch
new file mode 100644
index 0000000..ac0c141
--- /dev/null
+++ b/debian/patches/CVE-2016-0753.patch
@@ -0,0 +1,83 @@
+From 7a01874b75fdd62ab3626490cdf1c65c0ba659d0 Mon Sep 17 00:00:00 2001
+From: Aaron Patterson <aaron.patterson at gmail.com>
+Date: Mon, 18 Jan 2016 13:51:02 -0800
+Subject: [PATCH] Eliminate instance level writers for class accessors
+
+Instance level writers can have an impact on how the Active Model /
+Record objects are saved.  Specifically, they can be used to bypass
+validations.  This is a problem if mass assignment protection is
+disabled and specific attributes are passed to the constructor.
+
+Conflicts:
+	activerecord/lib/active_record/scoping/default.rb
+	activesupport/lib/active_support/callbacks.rb
+
+CVE-2016-0753
+---
+ activemodel/lib/active_model/serializers/json.rb | 2 +-
+ activemodel/lib/active_model/validations.rb      | 3 ++-
+ activerecord/lib/active_record/enum.rb           | 2 +-
+ activerecord/lib/active_record/reflection.rb     | 4 ++--
+ activesupport/lib/active_support/callbacks.rb    | 2 +-
+ 5 files changed, 7 insertions(+), 6 deletions(-)
+
+--- a/activemodel/lib/active_model/serializers/json.rb
++++ b/activemodel/lib/active_model/serializers/json.rb
+@@ -10,7 +10,7 @@ module ActiveModel
+       included do
+         extend ActiveModel::Naming
+ 
+-        class_attribute :include_root_in_json
++        class_attribute :include_root_in_json, instance_writer: false
+         self.include_root_in_json = false
+       end
+ 
+--- a/activemodel/lib/active_model/validations.rb
++++ b/activemodel/lib/active_model/validations.rb
+@@ -46,9 +46,10 @@ module ActiveModel
+       include HelperMethods
+ 
+       attr_accessor :validation_context
++      private :validation_context=
+       define_callbacks :validate, scope: :name
+ 
+-      class_attribute :_validators
++      class_attribute :_validators, instance_writer: false
+       self._validators = Hash.new { |h,k| h[k] = [] }
+     end
+ 
+--- a/activerecord/lib/active_record/enum.rb
++++ b/activerecord/lib/active_record/enum.rb
+@@ -68,7 +68,7 @@ module ActiveRecord
+   # Where conditions on an enum attribute must use the ordinal value of an enum.
+   module Enum
+     def self.extended(base) # :nodoc:
+-      base.class_attribute(:defined_enums)
++      base.class_attribute(:defined_enums, instance_writer: false)
+       base.defined_enums = {}
+     end
+ 
+--- a/activerecord/lib/active_record/reflection.rb
++++ b/activerecord/lib/active_record/reflection.rb
+@@ -4,8 +4,8 @@ module ActiveRecord
+     extend ActiveSupport::Concern
+ 
+     included do
+-      class_attribute :_reflections
+-      class_attribute :aggregate_reflections
++      class_attribute :_reflections, instance_writer: false
++      class_attribute :aggregate_reflections, instance_writer: false
+       self._reflections = {}
+       self.aggregate_reflections = {}
+     end
+--- a/activesupport/lib/active_support/callbacks.rb
++++ b/activesupport/lib/active_support/callbacks.rb
+@@ -726,7 +726,7 @@ module ActiveSupport
+         end
+ 
+         names.each do |name|
+-          class_attribute "_#{name}_callbacks"
++          class_attribute "_#{name}_callbacks", instance_writer: false
+           set_callbacks name, CallbackChain.new(name, options)
+         end
+       end
diff --git a/debian/patches/series b/debian/patches/series
index d2bcd8a..59c5cd6 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,9 @@
 be-carefull-with-that-bundler.patch
+CVE-2015-3226.patch
+CVE-2015-3227.patch
+CVE-2015-7576.patch
+CVE-2015-7577.patch
+CVE-2015-7581.patch
+CVE-2016-0751.patch
+CVE-2016-0752.patch
+CVE-2016-0753.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/rails.git



More information about the Pkg-ruby-extras-commits mailing list