Hello community,

here is the log from the commit of package rubygem-activestorage-5.2 for 
openSUSE:Factory checked in at 2018-12-06 12:17:46
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-activestorage-5.2 (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-activestorage-5.2.new.19453 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-activestorage-5.2"

Thu Dec  6 12:17:46 2018 rev:3 rq:655327 version:5.2.1.1

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/rubygem-activestorage-5.2/rubygem-activestorage-5.2.changes
      2018-08-12 20:53:38.761256926 +0200
+++ 
/work/SRC/openSUSE:Factory/.rubygem-activestorage-5.2.new.19453/rubygem-activestorage-5.2.changes
   2018-12-06 12:17:47.925488762 +0100
@@ -1,0 +2,32 @@
+Mon Dec  3 06:26:14 UTC 2018 - [email protected]
+ 
+- updated to version 5.2.1.1 (boo#1118076)
+
+- addresses a security vulnerability (CVE-2018-16477, boo#1117641)
+
+  Signed download URLs generated by `ActiveStorage` for Google Cloud Storage
+  service and Disk service include `content-disposition` and `content-type`
+  parameters that an attacker can modify. This can be used to upload specially
+  crafted HTML files and have them served and executed inline. Combined with
+  other techniques such as cookie bombing and specially crafted AppCache
+  manifests,
+  an attacker can gain access to private signed URLs within a specific
+  storage path.
+
+  Vulnerable apps are those using either GCS or the Disk service in
+  production.
+  Other storage services such as S3 or Azure aren't affected.
+
+  All users running an affected release should either upgrade or use one of
+  the
+  workarounds immediately. For those using GCS, it's also recommended to run
+  the
+  following to update existing blobs:
+
+  ```
+  ActiveStorage::Blob.find_each do |blob|
+    blob.send :update_service_metadata
+  end
+  ```
+
+-------------------------------------------------------------------

Old:
----
  activestorage-5.2.1.gem

New:
----
  activestorage-5.2.1.1.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-activestorage-5.2.spec ++++++
--- /var/tmp/diff_new_pack.w6LOr7/_old  2018-12-06 12:17:48.377488277 +0100
+++ /var/tmp/diff_new_pack.w6LOr7/_new  2018-12-06 12:17:48.377488277 +0100
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-activestorage-5.2
-Version:        5.2.1
+Version:        5.2.1.1
 Release:        0
 %define mod_name activestorage
 %define mod_full_name %{mod_name}-%{version}

++++++ activestorage-5.2.1.gem -> activestorage-5.2.1.1.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md    2018-08-07 23:42:20.000000000 +0200
+++ new/CHANGELOG.md    2018-11-27 21:12:28.000000000 +0100
@@ -1,3 +1,12 @@
+## Rails 5.2.1.1 (November 27, 2018) ##
+
+*   Prevent content type and disposition bypass in storage service URLs.
+
+    Fix CVE-2018-16477.
+
+    *Rosa Gutierrez*
+
+
 ## Rails 5.2.1 (August 07, 2018) ##
 
 *   Fix direct upload with zero-byte files.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/app/controllers/active_storage/disk_controller.rb 
new/app/controllers/active_storage/disk_controller.rb
--- old/app/controllers/active_storage/disk_controller.rb       2018-08-07 
23:42:20.000000000 +0200
+++ new/app/controllers/active_storage/disk_controller.rb       2018-11-27 
21:12:28.000000000 +0100
@@ -11,10 +11,10 @@
 
   def show
     if key = decode_verified_key
-      response.headers["Content-Type"] = params[:content_type] || 
DEFAULT_SEND_FILE_TYPE
-      response.headers["Content-Disposition"] = params[:disposition] || 
DEFAULT_SEND_FILE_DISPOSITION
+      response.headers["Content-Type"] = key[:content_type] || 
DEFAULT_SEND_FILE_TYPE
+      response.headers["Content-Disposition"] = key[:disposition] || 
DEFAULT_SEND_FILE_DISPOSITION
 
-      disk_service.download key do |chunk|
+      disk_service.download key[:key] do |chunk|
         response.stream.write chunk
       end
     else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/app/models/active_storage/blob/identifiable.rb 
new/app/models/active_storage/blob/identifiable.rb
--- old/app/models/active_storage/blob/identifiable.rb  2018-08-07 
23:42:20.000000000 +0200
+++ new/app/models/active_storage/blob/identifiable.rb  2018-11-27 
21:12:28.000000000 +0100
@@ -2,7 +2,10 @@
 
 module ActiveStorage::Blob::Identifiable
   def identify
-    update! content_type: identify_content_type, identified: true unless 
identified?
+    unless identified?
+      update! content_type: identify_content_type, identified: true
+      update_service_metadata
+    end
   end
 
   def identified?
@@ -17,4 +20,8 @@
     def download_identifiable_chunk
       service.download_chunk key, 0...4.kilobytes
     end
+
+    def update_service_metadata
+      service.update_metadata key, service_metadata if service_metadata.any?
+    end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/app/models/active_storage/blob.rb 
new/app/models/active_storage/blob.rb
--- old/app/models/active_storage/blob.rb       2018-08-07 23:42:20.000000000 
+0200
+++ new/app/models/active_storage/blob.rb       2018-11-27 21:12:28.000000000 
+0100
@@ -120,8 +120,8 @@
   def service_url(expires_in: service.url_expires_in, disposition: :inline, 
filename: nil, **options)
     filename = ActiveStorage::Filename.wrap(filename || self.filename)
 
-    service.url key, expires_in: expires_in, filename: filename, content_type: 
content_type,
-      disposition: forcibly_serve_as_binary? ? :attachment : disposition, 
**options
+    service.url key, expires_in: expires_in, filename: filename, content_type: 
content_type_for_service_url,
+      disposition: forced_disposition_for_service_url || disposition, **options
   end
 
   # Returns a URL that can be used to directly upload a file for this blob on 
the service. This URL is intended to be
@@ -152,7 +152,7 @@
     self.byte_size    = io.size
     self.identified   = true
 
-    service.upload(key, io, checksum: checksum)
+    service.upload key, io, checksum: checksum, **service_metadata
   end
 
   # Downloads the file associated with this blob. If no block is given, the 
entire file is read into memory and returned.
@@ -203,5 +203,29 @@
       ActiveStorage.content_types_to_serve_as_binary.include?(content_type)
     end
 
+    def allowed_inline?
+      ActiveStorage.content_types_allowed_inline.include?(content_type)
+    end
+
+    def content_type_for_service_url
+      forcibly_serve_as_binary? ? ActiveStorage.binary_content_type : 
content_type
+    end
+
+    def forced_disposition_for_service_url
+      if forcibly_serve_as_binary? || !allowed_inline?
+        :attachment
+      end
+    end
+
+    def service_metadata
+      if forcibly_serve_as_binary?
+        { content_type: ActiveStorage.binary_content_type, disposition: 
:attachment, filename: filename }
+      elsif !allowed_inline?
+        { content_type: content_type, disposition: :attachment, filename: 
filename }
+      else
+        { content_type: content_type }
+      end
+    end
+
     ActiveSupport.run_load_hooks(:active_storage_blob, self)
 end
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/engine.rb 
new/lib/active_storage/engine.rb
--- old/lib/active_storage/engine.rb    2018-08-07 23:42:20.000000000 +0200
+++ new/lib/active_storage/engine.rb    2018-11-27 21:12:28.000000000 +0100
@@ -37,6 +37,18 @@
       text/xml
       application/xml
       application/xhtml+xml
+      application/mathml+xml
+      text/cache-manifest
+    )
+
+    config.active_storage.content_types_allowed_inline = %w(
+      image/png
+      image/gif
+      image/jpg
+      image/jpeg
+      image/vnd.adobe.photoshop
+      image/vnd.microsoft.icon
+      application/pdf
     )
 
     config.eager_load_namespaces << ActiveStorage
@@ -51,6 +63,8 @@
 
         ActiveStorage.variable_content_types = 
app.config.active_storage.variable_content_types || []
         ActiveStorage.content_types_to_serve_as_binary = 
app.config.active_storage.content_types_to_serve_as_binary || []
+        ActiveStorage.content_types_allowed_inline = 
app.config.active_storage.content_types_allowed_inline || []
+        ActiveStorage.binary_content_type = 
app.config.active_storage.binary_content_type || "application/octet-stream"
       end
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/gem_version.rb 
new/lib/active_storage/gem_version.rb
--- old/lib/active_storage/gem_version.rb       2018-08-07 23:42:20.000000000 
+0200
+++ new/lib/active_storage/gem_version.rb       2018-11-27 21:12:28.000000000 
+0100
@@ -10,7 +10,7 @@
     MAJOR = 5
     MINOR = 2
     TINY  = 1
-    PRE   = nil
+    PRE   = "1"
 
     STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/service/azure_storage_service.rb 
new/lib/active_storage/service/azure_storage_service.rb
--- old/lib/active_storage/service/azure_storage_service.rb     2018-08-07 
23:42:20.000000000 +0200
+++ new/lib/active_storage/service/azure_storage_service.rb     2018-11-27 
21:12:28.000000000 +0100
@@ -17,7 +17,7 @@
       @container = container
     end
 
-    def upload(key, io, checksum: nil)
+    def upload(key, io, checksum: nil, **)
       instrument :upload, key: key, checksum: checksum do
         begin
           blobs.create_block_blob(container, key, IO.try_convert(io) || io, 
content_md5: checksum)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/service/disk_service.rb 
new/lib/active_storage/service/disk_service.rb
--- old/lib/active_storage/service/disk_service.rb      2018-08-07 
23:42:20.000000000 +0200
+++ new/lib/active_storage/service/disk_service.rb      2018-11-27 
21:12:28.000000000 +0100
@@ -15,7 +15,7 @@
       @root = root
     end
 
-    def upload(key, io, checksum: nil)
+    def upload(key, io, checksum: nil, **)
       instrument :upload, key: key, checksum: checksum do
         IO.copy_stream(io, make_path_for(key))
         ensure_integrity_of(key, checksum) if checksum
@@ -75,17 +75,23 @@
 
     def url(key, expires_in:, filename:, disposition:, content_type:)
       instrument :url, key: key do |payload|
-        verified_key_with_expiration = ActiveStorage.verifier.generate(key, 
expires_in: expires_in, purpose: :blob_key)
-
-        generated_url =
-          url_helpers.rails_disk_service_url(
-            verified_key_with_expiration,
-            host: current_host,
-            filename: filename,
-            disposition: content_disposition_with(type: disposition, filename: 
filename),
+        content_disposition = content_disposition_with(type: disposition, 
filename: filename)
+        verified_key_with_expiration = ActiveStorage.verifier.generate(
+          {
+            key: key,
+            disposition: content_disposition,
             content_type: content_type
-          )
-
+          },
+          { expires_in: expires_in,
+          purpose: :blob_key }
+        )
+
+        generated_url = 
url_helpers.rails_disk_service_url(verified_key_with_expiration,
+          host: current_host,
+          disposition: content_disposition,
+          content_type: content_type,
+          filename: filename
+        )
         payload[:url] = generated_url
 
         generated_url
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/service/gcs_service.rb 
new/lib/active_storage/service/gcs_service.rb
--- old/lib/active_storage/service/gcs_service.rb       2018-08-07 
23:42:20.000000000 +0200
+++ new/lib/active_storage/service/gcs_service.rb       2018-11-27 
21:12:28.000000000 +0100
@@ -15,21 +15,29 @@
       @config = config
     end
 
-    def upload(key, io, checksum: nil)
+    def upload(key, io, checksum: nil, content_type: nil, disposition: nil, 
filename: nil)
       instrument :upload, key: key, checksum: checksum do
         begin
-          # The official GCS client library doesn't allow us to create a file 
with no Content-Type metadata.
-          # We need the file we create to have no Content-Type so we can 
control it via the response-content-type
-          # param in signed URLs. Workaround: let the GCS client create the 
file with an inferred
-          # Content-Type (usually "application/octet-stream") then clear it.
-          bucket.create_file(io, key, md5: checksum).update do |file|
-            file.content_type = nil
-          end
+          # GCS's signed URLs don't include params such as 
response-content-type response-content_disposition
+          # in the signature, which means an attacker can modify them and 
bypass our effort to force these to
+          # binary and attachment when the file's content type requires it. 
The only way to force them is to
+          # store them as object's metadata.
+          content_disposition = content_disposition_with(type: disposition, 
filename: filename) if disposition && filename
+          bucket.create_file(io, key, md5: checksum, content_type: 
content_type, content_disposition: content_disposition)
         rescue Google::Cloud::InvalidArgumentError
           raise ActiveStorage::IntegrityError
         end
       end
     end
+
+    def update_metadata(key, content_type:, disposition: nil, filename: nil)
+      instrument :update_metadata, key: key, content_type: content_type, 
disposition: disposition do
+        file_for(key).update do |file|
+          file.content_type = content_type
+          file.content_disposition = content_disposition_with(type: 
disposition, filename: filename) if disposition && filename
+        end
+      end
+    end
 
     # FIXME: Download in chunks when given a block.
     def download(key)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/service/mirror_service.rb 
new/lib/active_storage/service/mirror_service.rb
--- old/lib/active_storage/service/mirror_service.rb    2018-08-07 
23:42:20.000000000 +0200
+++ new/lib/active_storage/service/mirror_service.rb    2018-11-27 
21:12:28.000000000 +0100
@@ -24,9 +24,9 @@
 
     # Upload the +io+ to the +key+ specified to all services. If a +checksum+ 
is provided, all services will
     # ensure a match when the upload has completed or raise an 
ActiveStorage::IntegrityError.
-    def upload(key, io, checksum: nil)
+    def upload(key, io, checksum: nil, **options)
       each_service.collect do |service|
-        service.upload key, io.tap(&:rewind), checksum: checksum
+        service.upload key, io.tap(&:rewind), checksum: checksum, **options
       end
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage/service.rb 
new/lib/active_storage/service.rb
--- old/lib/active_storage/service.rb   2018-08-07 23:42:20.000000000 +0200
+++ new/lib/active_storage/service.rb   2018-11-27 21:12:28.000000000 +0100
@@ -64,10 +64,16 @@
 
     # Upload the +io+ to the +key+ specified. If a +checksum+ is provided, the 
service will
     # ensure a match when the upload has completed or raise an 
ActiveStorage::IntegrityError.
-    def upload(key, io, checksum: nil)
+    def upload(key, io, checksum: nil, **options)
       raise NotImplementedError
     end
 
+    # Update metadata for the file identified by +key+ in the service.
+    # Override in subclasses only if the service needs to store specific
+    # metadata that has to be updated upon identification.
+    def update_metadata(key, **metadata)
+    end
+
     # Return the content of the file at the +key+.
     def download(key)
       raise NotImplementedError
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/active_storage.rb new/lib/active_storage.rb
--- old/lib/active_storage.rb   2018-08-07 23:42:20.000000000 +0200
+++ new/lib/active_storage.rb   2018-11-27 21:12:28.000000000 +0100
@@ -48,4 +48,6 @@
   mattr_accessor :paths, default: {}
   mattr_accessor :variable_content_types, default: []
   mattr_accessor :content_types_to_serve_as_binary, default: []
+  mattr_accessor :content_types_allowed_inline, default: []
+  mattr_accessor :binary_content_type, default: "application/octet-stream"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2018-08-07 23:42:20.000000000 +0200
+++ new/metadata        2018-11-27 21:12:28.000000000 +0100
@@ -1,14 +1,14 @@
 --- !ruby/object:Gem::Specification
 name: activestorage
 version: !ruby/object:Gem::Version
-  version: 5.2.1
+  version: 5.2.1.1
 platform: ruby
 authors:
 - David Heinemeier Hansson
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2018-08-07 00:00:00.000000000 Z
+date: 2018-11-27 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: actionpack
@@ -16,28 +16,28 @@
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 5.2.1
+        version: 5.2.1.1
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 5.2.1
+        version: 5.2.1.1
 - !ruby/object:Gem::Dependency
   name: activerecord
   requirement: !ruby/object:Gem::Requirement
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 5.2.1
+        version: 5.2.1.1
   type: :runtime
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
     requirements:
     - - '='
       - !ruby/object:Gem::Version
-        version: 5.2.1
+        version: 5.2.1.1
 - !ruby/object:Gem::Dependency
   name: marcel
   requirement: !ruby/object:Gem::Requirement
@@ -124,8 +124,8 @@
 licenses:
 - MIT
 metadata:
-  source_code_uri: https://github.com/rails/rails/tree/v5.2.1/activestorage
-  changelog_uri: 
https://github.com/rails/rails/blob/v5.2.1/activestorage/CHANGELOG.md
+  source_code_uri: https://github.com/rails/rails/tree/v5.2.1.1/activestorage
+  changelog_uri: 
https://github.com/rails/rails/blob/v5.2.1.1/activestorage/CHANGELOG.md
 post_install_message: 
 rdoc_options: []
 require_paths:


Reply via email to