[DRE-commits] [ruby-redis-store] 02/06: Add CVE-2017-1000248.patch (Closes: #882034)

Cédric Boutillier boutil at moszumanska.debian.org
Wed Nov 29 09:38:43 UTC 2017


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

boutil pushed a commit to branch unstable/master
in repository ruby-redis-store.

commit a03cabfe86374f1b99075ba355cb72be9deb356e
Author: Cédric Boutillier <boutil at debian.org>
Date:   Wed Nov 29 10:07:40 2017 +0100

    Add CVE-2017-1000248.patch (Closes: #882034)
---
 debian/patches/CVE-2017-1000248.patch | 551 ++++++++++++++++++++++++++++++++++
 debian/patches/series                 |   1 +
 2 files changed, 552 insertions(+)

diff --git a/debian/patches/CVE-2017-1000248.patch b/debian/patches/CVE-2017-1000248.patch
new file mode 100644
index 0000000..44c91de
--- /dev/null
+++ b/debian/patches/CVE-2017-1000248.patch
@@ -0,0 +1,551 @@
+Description: Replace marshalling with pluggable serializers
+Author: Tom Scott <tscott at weblinc.com>
+Bug: https://github.com/redis-store/redis-store/issues/289
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=882034
+Applied-Upstream: https://github.com/redis-store/redis-store/commit/e0c1398d54a9661c8c70267c3a925ba6b192142e
+Origin: upstream
+Last-Update: Tue, 15 Aug 2017 11:07:07 -0400
+
+This is in response to a vulnerability warning we received on Friday,
+August 11th, 2017. While most users will not be affected by this
+change, we recommend that developers of new applications use a different
+serializer other than `Marshal`. This, along with the removal of the
+`:marshalling` option, will enforce "sane defaults" in terms of securely
+serializing/de-serializing data.
+
+- Add `:serializer` option and deprecate `:marshalling`. Although you
+  will still be able to enable/disable serialization with Marshal using
+  `:marshalling` in the 1.x series, this will be removed by 2.0.
+
+- Rename `Redis::Store::Marshalling` to `Redis::Store::Serialization` to
+  reflect its new purpose.
+
+Fixes #289
+---
+ lib/redis-store.rb                                 | 12 -------
+ lib/redis/store.rb                                 | 28 +++++++++++++--
+ lib/redis/store/factory.rb                         |  9 ++++-
+ lib/redis/store/namespace.rb                       |  4 +--
+ .../store/{marshalling.rb => serialization.rb}     |  6 ++--
+ test/redis/store/factory_test.rb                   | 40 ++++++++++++++++++++--
+ test/redis/store/namespace_test.rb                 |  4 +--
+ .../{marshalling_test.rb => serialization_test.rb} |  4 +--
+ 8 files changed, 80 insertions(+), 27 deletions(-)
+ rename lib/redis/store/{marshalling.rb => serialization.rb} (90%)
+ rename test/redis/store/{marshalling_test.rb => serialization_test.rb} (98%)
+
+--- a/lib/redis-store.rb
++++ b/lib/redis-store.rb
+@@ -1,12 +1 @@
+-require 'redis'
+ require 'redis/store'
+-require 'redis/store/factory'
+-require 'redis/distributed_store'
+-require 'redis/store/namespace'
+-require 'redis/store/marshalling'
+-require 'redis/store/version'
+-
+-class Redis
+-  class Store < self
+-  end
+-end
+--- a/lib/redis/store.rb
++++ b/lib/redis/store.rb
+@@ -1,3 +1,9 @@
++require 'redis'
++require 'redis/store/factory'
++require 'redis/distributed_store'
++require 'redis/store/namespace'
++require 'redis/store/serialization'
++require 'redis/store/version'
+ require 'redis/store/ttl'
+ require 'redis/store/interface'
+ 
+@@ -7,6 +13,24 @@
+ 
+     def initialize(options = { })
+       super
++
++      unless options[:marshalling].nil?
++        puts %(
++          DEPRECATED: You are passing the :marshalling option, which has been
++          replaced with `serializer: Marshal` to support pluggable serialization
++          backends. To disable serialization (much like disabling marshalling),
++          pass `serializer: nil` in your configuration.
++
++          The :marshalling option will be removed for redis-store 2.0.
++        )
++      end
++
++      @serializer = options.key?(:serializer) ? options[:serializer] : Marshal
++
++      unless options[:marshalling].nil?
++        @serializer = options[:marshalling] ? Marshal : nil
++      end
++
+       _extend_marshalling options
+       _extend_namespace   options
+     end
+@@ -22,8 +46,7 @@
+ 
+     private
+       def _extend_marshalling(options)
+-        @marshalling = !(options[:marshalling] === false) # HACK - TODO delegate to Factory
+-        extend Marshalling if @marshalling
++        extend Serialization unless @serializer.nil?
+       end
+ 
+       def _extend_namespace(options)
+--- a/lib/redis/store/marshalling.rb
++++ /dev/null
+@@ -1,56 +0,0 @@
+-class Redis
+-  class Store < self
+-    module Marshalling
+-      def set(key, value, options = nil)
+-        _marshal(value, options) { |value| super encode(key), encode(value), options }
+-      end
+-
+-      def setnx(key, value, options = nil)
+-        _marshal(value, options) { |value| super encode(key), encode(value), options }
+-      end
+-
+-      def setex(key, expiry, value, options = nil)
+-        _marshal(value, options) { |value| super encode(key), expiry, encode(value), options }
+-      end
+-
+-      def get(key, options = nil)
+-        _unmarshal super(key), options
+-      end
+-
+-      def mget(*keys)
+-        options = keys.pop if keys.last.is_a?(Hash)
+-        super(*keys).map do |result|
+-          _unmarshal result, options
+-        end
+-      end
+-
+-      private
+-        def _marshal(val, options)
+-          yield marshal?(options) ? Marshal.dump(val) : val
+-        end
+-
+-        def _unmarshal(val, options)
+-          unmarshal?(val, options) ? Marshal.load(val) : val
+-        end
+-
+-        def marshal?(options)
+-          !(options && options[:raw])
+-        end
+-
+-        def unmarshal?(result, options)
+-          result && result.size > 0 && marshal?(options)
+-        end
+-
+-        if defined?(Encoding)
+-          def encode(string)
+-            key = string.to_s.dup
+-            key.force_encoding(Encoding::BINARY)
+-          end
+-        else
+-          def encode(string)
+-            string
+-          end
+-        end
+-    end
+-  end
+-end
+--- /dev/null
++++ b/lib/redis/store/serialization.rb
+@@ -0,0 +1,56 @@
++class Redis
++  class Store < self
++    module Serialization
++      def set(key, value, options = nil)
++        _marshal(value, options) { |value| super encode(key), encode(value), options }
++      end
++
++      def setnx(key, value, options = nil)
++        _marshal(value, options) { |value| super encode(key), encode(value), options }
++      end
++
++      def setex(key, expiry, value, options = nil)
++        _marshal(value, options) { |value| super encode(key), expiry, encode(value), options }
++      end
++
++      def get(key, options = nil)
++        _unmarshal super(key), options
++      end
++
++      def mget(*keys)
++        options = keys.pop if keys.last.is_a?(Hash)
++        super(*keys).map do |result|
++          _unmarshal result, options
++        end
++      end
++
++      private
++        def _marshal(val, options)
++          yield marshal?(options) ? @serializer.dump(val) : val
++        end
++
++        def _unmarshal(val, options)
++          unmarshal?(val, options) ? @serializer.load(val) : val
++        end
++
++        def marshal?(options)
++          !(options && options[:raw])
++        end
++
++        def unmarshal?(result, options)
++          result && result.size > 0 && marshal?(options)
++        end
++
++        if defined?(Encoding)
++          def encode(string)
++            key = string.to_s.dup
++            key.force_encoding(Encoding::BINARY)
++          end
++        else
++          def encode(string)
++            string
++          end
++        end
++    end
++  end
++end
+--- a/test/redis/store/factory_test.rb
++++ b/test/redis/store/factory_test.rb
+@@ -1,4 +1,5 @@
+ require 'test_helper'
++require 'json'
+ 
+ describe "Redis::Store::Factory" do
+   describe ".create" do
+@@ -41,9 +42,11 @@
+         store.instance_variable_get(:@client).password.must_equal("secret")
+       end
+ 
+-      it "allows/disable marshalling" do
+-        store = Redis::Store::Factory.create :marshalling => false
+-        store.instance_variable_get(:@marshalling).must_equal(false)
++
++      it "disables serialization" do
++        store = Redis::Store::Factory.create :serializer => nil
++        store.instance_variable_get(:@serializer).must_be_nil
++        store.instance_variable_get(:@options)[:raw].must_equal(true)
+       end
+ 
+       it "should instantiate a Redis::DistributedStore store" do
+--- a/test/redis/store/namespace_test.rb
++++ b/test/redis/store/namespace_test.rb
+@@ -3,7 +3,7 @@
+ describe "Redis::Store::Namespace" do
+   def setup
+     @namespace = "theplaylist"
+-    @store  = Redis::Store.new :namespace => @namespace, :marshalling => false # TODO remove mashalling option
++    @store  = Redis::Store.new :namespace => @namespace, :serializer => nil
+     @client = @store.instance_variable_get(:@client)
+     @rabbit = "bunny"
+     @default_store = Redis::Store.new
+@@ -77,7 +77,7 @@
+   end
+ 
+   describe 'method calls' do
+-    let(:store){Redis::Store.new :namespace => @namespace, :marshalling => false}
++    let(:store){Redis::Store.new :namespace => @namespace, :serializer => nil}
+     let(:client){store.instance_variable_get(:@client)}
+ 
+     it "should namespace get" do
+--- a/test/redis/store/marshalling_test.rb
++++ /dev/null
+@@ -1,128 +0,0 @@
+-require 'test_helper'
+-
+-describe "Redis::Marshalling" do
+-  def setup
+-    @store = Redis::Store.new :marshalling => true
+-    @rabbit = OpenStruct.new :name => "bunny"
+-    @white_rabbit = OpenStruct.new :color => "white"
+-    @store.set "rabbit", @rabbit
+-    @store.del "rabbit2"
+-  end
+-
+-  def teardown
+-    @store.flushdb
+-    @store.quit
+-  end
+-
+-  it "unmarshals on get" do
+-    @store.get("rabbit").must_equal(@rabbit)
+-  end
+-
+-  it "marshals on set" do
+-    @store.set "rabbit", @white_rabbit
+-    @store.get("rabbit").must_equal(@white_rabbit)
+-  end
+-
+-  if RUBY_VERSION.match /1\.9/
+-    it "doesn't unmarshal on get if raw option is true" do
+-      @store.get("rabbit", :raw => true).must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
+-    end
+-  else
+-    it "doesn't unmarshal on get if raw option is true" do
+-      @store.get("rabbit", :raw => true).must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
+-    end
+-  end
+-
+-  it "doesn't marshal set if raw option is true" do
+-    @store.set "rabbit", @white_rabbit, :raw => true
+-    @store.get("rabbit", :raw => true).must_equal(%(#<OpenStruct color="white">))
+-  end
+-
+-  it "doesn't unmarshal if get returns an empty string" do
+-    @store.set "empty_string", ""
+-    @store.get("empty_string").must_equal("")
+-    # TODO use a meaningful Exception
+-    # lambda { @store.get("empty_string").must_equal("") }.wont_raise Exception
+-  end
+-
+-  it "doesn't set an object if already exist" do
+-    @store.setnx "rabbit", @white_rabbit
+-    @store.get("rabbit").must_equal(@rabbit)
+-  end
+-
+-  it "marshals on set unless exists" do
+-    @store.setnx "rabbit2", @white_rabbit
+-    @store.get("rabbit2").must_equal(@white_rabbit)
+-  end
+-
+-  it "doesn't marshal on set unless exists if raw option is true" do
+-    @store.setnx "rabbit2", @white_rabbit, :raw => true
+-    @store.get("rabbit2", :raw => true).must_equal(%(#<OpenStruct color="white">))
+-  end
+-
+-  it "marshals on set expire" do
+-    @store.setex "rabbit2", 1, @white_rabbit
+-    @store.get("rabbit2").must_equal(@white_rabbit)
+-    sleep 2
+-    @store.get("rabbit2").must_be_nil
+-  end
+-
+-  it "doesn't unmarshal on multi get" do
+-    @store.set "rabbit2", @white_rabbit
+-    rabbit, rabbit2 = @store.mget "rabbit", "rabbit2"
+-    rabbit.must_equal(@rabbit)
+-    rabbit2.must_equal(@white_rabbit)
+-  end
+-
+-  if RUBY_VERSION.match /1\.9/
+-    it "doesn't unmarshal on multi get if raw option is true" do
+-      @store.set "rabbit2", @white_rabbit
+-      rabbit, rabbit2 = @store.mget "rabbit", "rabbit2", :raw => true
+-      rabbit.must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
+-      rabbit2.must_equal("\x04\bU:\x0FOpenStruct{\x06:\ncolorI\"\nwhite\x06:\x06EF")
+-    end
+-  else
+-    it "doesn't unmarshal on multi get if raw option is true" do
+-      @store.set "rabbit2", @white_rabbit
+-      rabbit, rabbit2 = @store.mget "rabbit", "rabbit2", :raw => true
+-      rabbit.must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
+-      rabbit2.must_include("\x04\bU:\x0FOpenStruct{\x06:\ncolor")
+-    end
+-  end
+-
+-  describe "binary safety" do
+-    it "marshals objects" do
+-      utf8_key = [51339].pack("U*")
+-      ascii_rabbit = OpenStruct.new(:name => [128].pack("C*"))
+-
+-      @store.set(utf8_key, ascii_rabbit)
+-      @store.get(utf8_key).must_equal(ascii_rabbit)
+-    end
+-
+-    it "gets and sets raw values" do
+-      utf8_key = [51339].pack("U*")
+-      ascii_string = [128].pack("C*")
+-
+-      @store.set(utf8_key, ascii_string, :raw => true)
+-      @store.get(utf8_key, :raw => true).bytes.to_a.must_equal(ascii_string.bytes.to_a)
+-    end
+-
+-    it "marshals objects on setnx" do
+-      utf8_key = [51339].pack("U*")
+-      ascii_rabbit = OpenStruct.new(:name => [128].pack("C*"))
+-
+-      @store.del(utf8_key)
+-      @store.setnx(utf8_key, ascii_rabbit)
+-      @store.get(utf8_key).must_equal(ascii_rabbit)
+-    end
+-
+-    it "gets and sets raw values on setnx" do
+-      utf8_key = [51339].pack("U*")
+-      ascii_string = [128].pack("C*")
+-
+-      @store.del(utf8_key)
+-      @store.setnx(utf8_key, ascii_string, :raw => true)
+-      @store.get(utf8_key, :raw => true).bytes.to_a.must_equal(ascii_string.bytes.to_a)
+-    end
+-  end if defined?(Encoding)
+-end
+--- /dev/null
++++ b/test/redis/store/serialization_test.rb
+@@ -0,0 +1,128 @@
++require 'test_helper'
++
++describe "Redis::Serialization" do
++  def setup
++    @store = Redis::Store.new serializer: Marshal
++    @rabbit = OpenStruct.new :name => "bunny"
++    @white_rabbit = OpenStruct.new :color => "white"
++    @store.set "rabbit", @rabbit
++    @store.del "rabbit2"
++  end
++
++  def teardown
++    @store.flushdb
++    @store.quit
++  end
++
++  it "unmarshals on get" do
++    @store.get("rabbit").must_equal(@rabbit)
++  end
++
++  it "marshals on set" do
++    @store.set "rabbit", @white_rabbit
++    @store.get("rabbit").must_equal(@white_rabbit)
++  end
++
++  if RUBY_VERSION.match /1\.9/
++    it "doesn't unmarshal on get if raw option is true" do
++      @store.get("rabbit", :raw => true).must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
++    end
++  else
++    it "doesn't unmarshal on get if raw option is true" do
++      @store.get("rabbit", :raw => true).must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
++    end
++  end
++
++  it "doesn't marshal set if raw option is true" do
++    @store.set "rabbit", @white_rabbit, :raw => true
++    @store.get("rabbit", :raw => true).must_equal(%(#<OpenStruct color="white">))
++  end
++
++  it "doesn't unmarshal if get returns an empty string" do
++    @store.set "empty_string", ""
++    @store.get("empty_string").must_equal("")
++    # TODO use a meaningful Exception
++    # lambda { @store.get("empty_string").must_equal("") }.wont_raise Exception
++  end
++
++  it "doesn't set an object if already exist" do
++    @store.setnx "rabbit", @white_rabbit
++    @store.get("rabbit").must_equal(@rabbit)
++  end
++
++  it "marshals on set unless exists" do
++    @store.setnx "rabbit2", @white_rabbit
++    @store.get("rabbit2").must_equal(@white_rabbit)
++  end
++
++  it "doesn't marshal on set unless exists if raw option is true" do
++    @store.setnx "rabbit2", @white_rabbit, :raw => true
++    @store.get("rabbit2", :raw => true).must_equal(%(#<OpenStruct color="white">))
++  end
++
++  it "marshals on set expire" do
++    @store.setex "rabbit2", 1, @white_rabbit
++    @store.get("rabbit2").must_equal(@white_rabbit)
++    sleep 2
++    @store.get("rabbit2").must_be_nil
++  end
++
++  it "doesn't unmarshal on multi get" do
++    @store.set "rabbit2", @white_rabbit
++    rabbit, rabbit2 = @store.mget "rabbit", "rabbit2"
++    rabbit.must_equal(@rabbit)
++    rabbit2.must_equal(@white_rabbit)
++  end
++
++  if RUBY_VERSION.match /1\.9/
++    it "doesn't unmarshal on multi get if raw option is true" do
++      @store.set "rabbit2", @white_rabbit
++      rabbit, rabbit2 = @store.mget "rabbit", "rabbit2", :raw => true
++      rabbit.must_equal("\x04\bU:\x0FOpenStruct{\x06:\tnameI\"\nbunny\x06:\x06EF")
++      rabbit2.must_equal("\x04\bU:\x0FOpenStruct{\x06:\ncolorI\"\nwhite\x06:\x06EF")
++    end
++  else
++    it "doesn't unmarshal on multi get if raw option is true" do
++      @store.set "rabbit2", @white_rabbit
++      rabbit, rabbit2 = @store.mget "rabbit", "rabbit2", :raw => true
++      rabbit.must_include("\x04\bU:\x0FOpenStruct{\x06:\tname")
++      rabbit2.must_include("\x04\bU:\x0FOpenStruct{\x06:\ncolor")
++    end
++  end
++
++  describe "binary safety" do
++    it "marshals objects" do
++      utf8_key = [51339].pack("U*")
++      ascii_rabbit = OpenStruct.new(:name => [128].pack("C*"))
++
++      @store.set(utf8_key, ascii_rabbit)
++      @store.get(utf8_key).must_equal(ascii_rabbit)
++    end
++
++    it "gets and sets raw values" do
++      utf8_key = [51339].pack("U*")
++      ascii_string = [128].pack("C*")
++
++      @store.set(utf8_key, ascii_string, :raw => true)
++      @store.get(utf8_key, :raw => true).bytes.to_a.must_equal(ascii_string.bytes.to_a)
++    end
++
++    it "marshals objects on setnx" do
++      utf8_key = [51339].pack("U*")
++      ascii_rabbit = OpenStruct.new(:name => [128].pack("C*"))
++
++      @store.del(utf8_key)
++      @store.setnx(utf8_key, ascii_rabbit)
++      @store.get(utf8_key).must_equal(ascii_rabbit)
++    end
++
++    it "gets and sets raw values on setnx" do
++      utf8_key = [51339].pack("U*")
++      ascii_string = [128].pack("C*")
++
++      @store.del(utf8_key)
++      @store.setnx(utf8_key, ascii_string, :raw => true)
++      @store.get(utf8_key, :raw => true).bytes.to_a.must_equal(ascii_string.bytes.to_a)
++    end
++  end if defined?(Encoding)
++end
+--- a/lib/redis/store/factory.rb
++++ b/lib/redis/store/factory.rb
+@@ -50,6 +50,14 @@
+         if options.key?(:key_prefix) && !options.key?(:namespace)
+           options[:namespace] = options.delete(:key_prefix) # RailsSessionStore
+         end
++        options[:raw] = case
++                        when options.key?(:serializer)
++                          options[:serializer].nil?
++                        when options.key?(:marshalling)
++                          !options[:marshalling]
++                        else
++                          false
++                        end
+         options
+       end
+ 
+--- a/lib/redis/store/namespace.rb
++++ b/lib/redis/store/namespace.rb
+@@ -44,8 +44,8 @@
+       def mget(*keys)
+         options = keys.pop if keys.last.is_a? Hash
+         if keys.any?
+-          # Marshalling gets extended before Namespace does, so we need to pass options further
+-          if singleton_class.ancestors.include? Marshalling
++          # Serialization gets extended before Namespace does, so we need to pass options further
++          if singleton_class.ancestors.include? Serialization
+             super *keys.map {|key| interpolate(key) }, options
+           else
+             super *keys.map {|key| interpolate(key) }
diff --git a/debian/patches/series b/debian/patches/series
index a51ad82..beee078 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,2 @@
 Bundler
+CVE-2017-1000248.patch

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



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