rack 2.0.9.2 → 2.0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/HISTORY.md +4 -0
- data/README.rdoc +17 -3
- data/lib/rack/multipart/parser.rb +16 -4
- data/lib/rack/utils.rb +15 -4
- data/lib/rack.rb +1 -1
- data/test/spec_multipart.rb +12 -0
- data/test/spec_request.rb +17 -1
- metadata +44 -44
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 60eb430d14b80b4cc729d7a97bdf1a56196fa854ff5bd0a23f4fd21ecabd92ec
         | 
| 4 | 
            +
              data.tar.gz: 373f537c5b38c9cf1f307dcc8876ff52e4dc67235bfcd554a0f6e35c854ee4c0
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d8d221546080d35fe8e9e4eb0810b02d0996b912874c408a7a5d270d6e26453430f0f05108ba41d8de40088b882db1de9f1efcac4e6b7e63a01431b6e4bd5f09
         | 
| 7 | 
            +
              data.tar.gz: f4ba080150f27b7d2ffb4babc9707c0e539a7464bb4377df192122d8484158d188be57474ba9b5af3f72eaebb7257977f2ad43ba7effe3068decccba84caa0ea
         | 
    
        data/HISTORY.md
    CHANGED
    
    | @@ -1,3 +1,7 @@ | |
| 1 | 
            +
            Thu Mar  2 14:50:46 2023  Aaron Patterson <tenderlove@ruby-lang.org>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            	* [CVE-2023-27530] Introduce multipart_total_part_limit to limit total parts
         | 
| 4 | 
            +
             | 
| 1 5 | 
             
            Tue Jan 17 12:27:04 2023  Aaron Patterson <tenderlove@ruby-lang.org>
         | 
| 2 6 |  | 
| 3 7 | 
             
                    * [CVE-2022-44571] Fix ReDoS vulnerability in multipart parser
         | 
    
        data/README.rdoc
    CHANGED
    
    | @@ -189,16 +189,30 @@ This helps prevent a rogue client from flooding a Request. | |
| 189 189 |  | 
| 190 190 | 
             
            Default to 65536 characters (4 kiB in worst case).
         | 
| 191 191 |  | 
| 192 | 
            -
            ===  | 
| 192 | 
            +
            === multipart_file_limit
         | 
| 193 193 |  | 
| 194 | 
            -
            The maximum number of parts a request can contain.
         | 
| 194 | 
            +
            The maximum number of parts with a filename a request can contain.
         | 
| 195 195 | 
             
            Accepting too many part can lead to the server running out of file handles.
         | 
| 196 196 |  | 
| 197 197 | 
             
            The default is 128, which means that a single request can't upload more than 128 files at once.
         | 
| 198 198 |  | 
| 199 199 | 
             
            Set to 0 for no limit.
         | 
| 200 200 |  | 
| 201 | 
            -
            Can also be set via the  | 
| 201 | 
            +
            Can also be set via the +RACK_MULTIPART_FILE_LIMIT+ environment variable.
         | 
| 202 | 
            +
             | 
| 203 | 
            +
            (This is also aliased as +multipart_part_limit+ and +RACK_MULTIPART_PART_LIMIT+ for compatibility)
         | 
| 204 | 
            +
             | 
| 205 | 
            +
            === multipart_total_part_limit
         | 
| 206 | 
            +
             | 
| 207 | 
            +
            The maximum total number of parts a request can contain of any type, including
         | 
| 208 | 
            +
            both file and non-file form fields.
         | 
| 209 | 
            +
             | 
| 210 | 
            +
            The default is 4096, which means that a single request can't contain more than
         | 
| 211 | 
            +
            4096 parts.
         | 
| 212 | 
            +
             | 
| 213 | 
            +
            Set to 0 for no limit.
         | 
| 214 | 
            +
             | 
| 215 | 
            +
            Can also be set via the +RACK_MULTIPART_TOTAL_PART_LIMIT+ environment variable.
         | 
| 202 216 |  | 
| 203 217 | 
             
            == History
         | 
| 204 218 |  | 
| @@ -3,6 +3,7 @@ require 'rack/utils' | |
| 3 3 | 
             
            module Rack
         | 
| 4 4 | 
             
              module Multipart
         | 
| 5 5 | 
             
                class MultipartPartLimitError < Errno::EMFILE; end
         | 
| 6 | 
            +
                class MultipartTotalPartLimitError < StandardError; end
         | 
| 6 7 |  | 
| 7 8 | 
             
                class Parser
         | 
| 8 9 | 
             
                  BUFSIZE = 16384
         | 
| @@ -138,7 +139,8 @@ module Rack | |
| 138 139 | 
             
                      end
         | 
| 139 140 |  | 
| 140 141 | 
             
                      @mime_parts[mime_index] = klass.new(body, head, filename, content_type, name)
         | 
| 141 | 
            -
             | 
| 142 | 
            +
             | 
| 143 | 
            +
                      check_part_limits
         | 
| 142 144 | 
             
                    end
         | 
| 143 145 |  | 
| 144 146 | 
             
                    def on_mime_body mime_index, content
         | 
| @@ -150,13 +152,23 @@ module Rack | |
| 150 152 |  | 
| 151 153 | 
             
                    private
         | 
| 152 154 |  | 
| 153 | 
            -
                    def  | 
| 154 | 
            -
                       | 
| 155 | 
            -
             | 
| 155 | 
            +
                    def check_part_limits
         | 
| 156 | 
            +
                      file_limit = Utils.multipart_file_limit
         | 
| 157 | 
            +
                      part_limit = Utils.multipart_total_part_limit
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                      if file_limit && file_limit > 0
         | 
| 160 | 
            +
                        if @open_files >= file_limit
         | 
| 156 161 | 
             
                          @mime_parts.each(&:close)
         | 
| 157 162 | 
             
                          raise MultipartPartLimitError, 'Maximum file multiparts in content reached'
         | 
| 158 163 | 
             
                        end
         | 
| 159 164 | 
             
                      end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                      if part_limit && part_limit > 0
         | 
| 167 | 
            +
                        if @mime_parts.size >= part_limit
         | 
| 168 | 
            +
                          @mime_parts.each(&:close)
         | 
| 169 | 
            +
                          raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached'
         | 
| 170 | 
            +
                        end
         | 
| 171 | 
            +
                      end
         | 
| 160 172 | 
             
                    end
         | 
| 161 173 | 
             
                  end
         | 
| 162 174 |  | 
    
        data/lib/rack/utils.rb
    CHANGED
    
    | @@ -53,13 +53,24 @@ module Rack | |
| 53 53 | 
             
                module_function :unescape
         | 
| 54 54 |  | 
| 55 55 | 
             
                class << self
         | 
| 56 | 
            -
                  attr_accessor : | 
| 56 | 
            +
                  attr_accessor :multipart_total_part_limit
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  attr_accessor :multipart_file_limit
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  # multipart_part_limit is the original name of multipart_file_limit, but
         | 
| 61 | 
            +
                  # the limit only counts parts with filenames.
         | 
| 62 | 
            +
                  alias multipart_part_limit multipart_file_limit
         | 
| 63 | 
            +
                  alias multipart_part_limit= multipart_file_limit=
         | 
| 57 64 | 
             
                end
         | 
| 58 65 |  | 
| 59 | 
            -
                # The maximum number of parts a request can contain. Accepting too | 
| 60 | 
            -
                # can lead to the server running out of file handles.
         | 
| 66 | 
            +
                # The maximum number of file parts a request can contain. Accepting too
         | 
| 67 | 
            +
                # many parts can lead to the server running out of file handles.
         | 
| 61 68 | 
             
                # Set to `0` for no limit.
         | 
| 62 | 
            -
                self. | 
| 69 | 
            +
                self.multipart_file_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || ENV['RACK_MULTIPART_FILE_LIMIT'] || 128).to_i
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                # The maximum total number of parts a request can contain. Accepting too
         | 
| 72 | 
            +
                # many can lead to excessive memory use and parsing time.
         | 
| 73 | 
            +
                self.multipart_total_part_limit = (ENV['RACK_MULTIPART_TOTAL_PART_LIMIT'] || 4096).to_i
         | 
| 63 74 |  | 
| 64 75 | 
             
                def self.param_depth_limit
         | 
| 65 76 | 
             
                  default_query_parser.param_depth_limit
         | 
    
        data/lib/rack.rb
    CHANGED
    
    
    
        data/test/spec_multipart.rb
    CHANGED
    
    | @@ -548,6 +548,18 @@ Content-Type: image/jpeg\r | |
| 548 548 | 
             
                end
         | 
| 549 549 | 
             
              end
         | 
| 550 550 |  | 
| 551 | 
            +
              it "reach a multipart total limit" do
         | 
| 552 | 
            +
                begin
         | 
| 553 | 
            +
                  previous_limit = Rack::Utils.multipart_total_part_limit
         | 
| 554 | 
            +
                  Rack::Utils.multipart_total_part_limit = 5
         | 
| 555 | 
            +
             | 
| 556 | 
            +
                  env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields)
         | 
| 557 | 
            +
                  lambda { Rack::Multipart.parse_multipart(env) }.must_raise Rack::Multipart::MultipartTotalPartLimitError
         | 
| 558 | 
            +
                ensure
         | 
| 559 | 
            +
                  Rack::Utils.multipart_total_part_limit = previous_limit
         | 
| 560 | 
            +
                end
         | 
| 561 | 
            +
              end
         | 
| 562 | 
            +
             | 
| 551 563 | 
             
              it "return nil if no UploadedFiles were used" do
         | 
| 552 564 | 
             
                data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}])
         | 
| 553 565 | 
             
                data.must_be_nil
         | 
    
        data/test/spec_request.rb
    CHANGED
    
    | @@ -911,7 +911,7 @@ EOF | |
| 911 911 | 
             
                f[:tempfile].size.must_equal 76
         | 
| 912 912 | 
             
              end
         | 
| 913 913 |  | 
| 914 | 
            -
              it "MultipartPartLimitError when request has too many multipart parts if limit set" do
         | 
| 914 | 
            +
              it "MultipartPartLimitError when request has too many multipart file parts if limit set" do
         | 
| 915 915 | 
             
                begin
         | 
| 916 916 | 
             
                  data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
         | 
| 917 917 | 
             
                  data += "--AaB03x--\r"
         | 
| @@ -927,6 +927,22 @@ EOF | |
| 927 927 | 
             
                end
         | 
| 928 928 | 
             
              end
         | 
| 929 929 |  | 
| 930 | 
            +
              it "MultipartPartLimitError when request has too many multipart total parts if limit set" do
         | 
| 931 | 
            +
                begin
         | 
| 932 | 
            +
                  data = 10000.times.map { "--AaB03x\r\ncontent-type: text/plain\r\ncontent-disposition: attachment; name=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
         | 
| 933 | 
            +
                  data += "--AaB03x--\r"
         | 
| 934 | 
            +
             | 
| 935 | 
            +
                  options = {
         | 
| 936 | 
            +
                    "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x",
         | 
| 937 | 
            +
                    "CONTENT_LENGTH" => data.length.to_s,
         | 
| 938 | 
            +
                    :input => StringIO.new(data)
         | 
| 939 | 
            +
                  }
         | 
| 940 | 
            +
             | 
| 941 | 
            +
                  request = make_request Rack::MockRequest.env_for("/", options)
         | 
| 942 | 
            +
                  lambda { request.POST }.must_raise Rack::Multipart::MultipartTotalPartLimitError
         | 
| 943 | 
            +
                end
         | 
| 944 | 
            +
              end
         | 
| 945 | 
            +
             | 
| 930 946 | 
             
              it 'closes tempfiles it created in the case of too many created' do
         | 
| 931 947 | 
             
                begin
         | 
| 932 948 | 
             
                  data = 10000.times.map { "--AaB03x\r\nContent-Type: text/plain\r\nContent-Disposition: attachment; name=#{SecureRandom.hex(10)}; filename=#{SecureRandom.hex(10)}\r\n\r\ncontents\r\n" }.join("\r\n")
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: rack
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.0.9. | 
| 4 | 
            +
              version: 2.0.9.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Leah Neukirchen
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-03-02 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: minitest
         | 
| @@ -275,60 +275,60 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 275 275 | 
             
                - !ruby/object:Gem::Version
         | 
| 276 276 | 
             
                  version: '0'
         | 
| 277 277 | 
             
            requirements: []
         | 
| 278 | 
            -
            rubygems_version: 3.1 | 
| 278 | 
            +
            rubygems_version: 3.4.1
         | 
| 279 279 | 
             
            signing_key:
         | 
| 280 280 | 
             
            specification_version: 4
         | 
| 281 281 | 
             
            summary: a modular Ruby webserver interface
         | 
| 282 282 | 
             
            test_files:
         | 
| 283 | 
            -
            - test/ | 
| 283 | 
            +
            - test/spec_auth_basic.rb
         | 
| 284 | 
            +
            - test/spec_auth_digest.rb
         | 
| 285 | 
            +
            - test/spec_body_proxy.rb
         | 
| 286 | 
            +
            - test/spec_builder.rb
         | 
| 287 | 
            +
            - test/spec_cascade.rb
         | 
| 288 | 
            +
            - test/spec_cgi.rb
         | 
| 289 | 
            +
            - test/spec_chunked.rb
         | 
| 290 | 
            +
            - test/spec_common_logger.rb
         | 
| 291 | 
            +
            - test/spec_conditional_get.rb
         | 
| 292 | 
            +
            - test/spec_config.rb
         | 
| 293 | 
            +
            - test/spec_content_length.rb
         | 
| 294 | 
            +
            - test/spec_content_type.rb
         | 
| 284 295 | 
             
            - test/spec_deflater.rb
         | 
| 285 | 
            -
            - test/ | 
| 286 | 
            -
            - test/spec_session_cookie.rb
         | 
| 287 | 
            -
            - test/spec_session_pool.rb
         | 
| 296 | 
            +
            - test/spec_directory.rb
         | 
| 288 297 | 
             
            - test/spec_etag.rb
         | 
| 289 | 
            -
            - test/ | 
| 298 | 
            +
            - test/spec_events.rb
         | 
| 299 | 
            +
            - test/spec_fastcgi.rb
         | 
| 300 | 
            +
            - test/spec_file.rb
         | 
| 290 301 | 
             
            - test/spec_handler.rb
         | 
| 291 | 
            -
            - test/ | 
| 292 | 
            -
            - test/ | 
| 293 | 
            -
            - test/ | 
| 294 | 
            -
            - test/ | 
| 295 | 
            -
            - test/ | 
| 302 | 
            +
            - test/spec_head.rb
         | 
| 303 | 
            +
            - test/spec_lint.rb
         | 
| 304 | 
            +
            - test/spec_lobster.rb
         | 
| 305 | 
            +
            - test/spec_lock.rb
         | 
| 306 | 
            +
            - test/spec_logger.rb
         | 
| 296 307 | 
             
            - test/spec_media_type.rb
         | 
| 297 | 
            -
            - test/spec_cgi.rb
         | 
| 298 308 | 
             
            - test/spec_method_override.rb
         | 
| 299 | 
            -
            - test/ | 
| 300 | 
            -
            - test/ | 
| 309 | 
            +
            - test/spec_mime.rb
         | 
| 310 | 
            +
            - test/spec_mock.rb
         | 
| 311 | 
            +
            - test/spec_multipart.rb
         | 
| 312 | 
            +
            - test/spec_null_logger.rb
         | 
| 313 | 
            +
            - test/spec_recursive.rb
         | 
| 301 314 | 
             
            - test/spec_request.rb
         | 
| 302 | 
            -
            - test/ | 
| 303 | 
            -
            - test/ | 
| 315 | 
            +
            - test/spec_response.rb
         | 
| 316 | 
            +
            - test/spec_rewindable_input.rb
         | 
| 304 317 | 
             
            - test/spec_runtime.rb
         | 
| 305 | 
            -
            - test/spec_session_persisted_secure_secure_session_hash.rb
         | 
| 306 | 
            -
            - test/spec_fastcgi.rb
         | 
| 307 | 
            -
            - test/spec_common_logger.rb
         | 
| 308 | 
            -
            - test/spec_builder.rb
         | 
| 309 | 
            -
            - test/spec_config.rb
         | 
| 310 | 
            -
            - test/spec_utils.rb
         | 
| 311 318 | 
             
            - test/spec_sendfile.rb
         | 
| 312 | 
            -
            - test/spec_lobster.rb
         | 
| 313 | 
            -
            - test/spec_lint.rb
         | 
| 314 | 
            -
            - test/spec_conditional_get.rb
         | 
| 315 | 
            -
            - test/spec_tempfile_reaper.rb
         | 
| 316 | 
            -
            - test/spec_mock.rb
         | 
| 317 319 | 
             
            - test/spec_server.rb
         | 
| 318 | 
            -
            - test/ | 
| 319 | 
            -
            - test/ | 
| 320 | 
            -
            - test/ | 
| 321 | 
            -
            - test/ | 
| 320 | 
            +
            - test/spec_session_abstract_id.rb
         | 
| 321 | 
            +
            - test/spec_session_abstract_session_hash.rb
         | 
| 322 | 
            +
            - test/spec_session_cookie.rb
         | 
| 323 | 
            +
            - test/spec_session_memcache.rb
         | 
| 324 | 
            +
            - test/spec_session_persisted_secure_secure_session_hash.rb
         | 
| 325 | 
            +
            - test/spec_session_pool.rb
         | 
| 326 | 
            +
            - test/spec_show_exceptions.rb
         | 
| 322 327 | 
             
            - test/spec_show_status.rb
         | 
| 323 | 
            -
            - test/ | 
| 324 | 
            -
            - test/ | 
| 325 | 
            -
            - test/ | 
| 328 | 
            +
            - test/spec_static.rb
         | 
| 329 | 
            +
            - test/spec_tempfile_reaper.rb
         | 
| 330 | 
            +
            - test/spec_thin.rb
         | 
| 326 331 | 
             
            - test/spec_urlmap.rb
         | 
| 327 | 
            -
            - test/ | 
| 328 | 
            -
            - test/ | 
| 329 | 
            -
            - test/ | 
| 330 | 
            -
            - test/spec_head.rb
         | 
| 331 | 
            -
            - test/spec_lock.rb
         | 
| 332 | 
            -
            - test/spec_rewindable_input.rb
         | 
| 333 | 
            -
            - test/spec_session_memcache.rb
         | 
| 334 | 
            -
            - test/spec_content_length.rb
         | 
| 332 | 
            +
            - test/spec_utils.rb
         | 
| 333 | 
            +
            - test/spec_version.rb
         | 
| 334 | 
            +
            - test/spec_webrick.rb
         |