rack 2.0.9.2 → 2.0.9.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc237005e0685c87558593892557c95cd2b19a69344a5e7730861c4737710068
4
- data.tar.gz: c6f06fabfb75b648b39013635615bb0c234b46e06bb21ee0d34fa984bc8a4327
3
+ metadata.gz: 60eb430d14b80b4cc729d7a97bdf1a56196fa854ff5bd0a23f4fd21ecabd92ec
4
+ data.tar.gz: 373f537c5b38c9cf1f307dcc8876ff52e4dc67235bfcd554a0f6e35c854ee4c0
5
5
  SHA512:
6
- metadata.gz: 91d96b990c872a04ed4dfc6eeea2ee24c7229d1bc382fb19ee56a2d63df67ef155e76e2ff760b5fce600101bf49f4359ed021959f1d72789821c71db4653e67a
7
- data.tar.gz: bf4aceee4f04788e44dac8838ff210be458f6869264c380da218ad1d8f60651900212c6f2b6e1909666d9861a2d7865a85da8b4ff836b5ad075d3fe7cf9293f2
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
- === multipart_part_limit
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 RACK_MULTIPART_PART_LIMIT environment variable.
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
- check_open_files
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 check_open_files
154
- if Utils.multipart_part_limit > 0
155
- if @open_files >= Utils.multipart_part_limit
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 :multipart_part_limit
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 many part
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.multipart_part_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || 128).to_i
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
@@ -18,7 +18,7 @@ module Rack
18
18
  VERSION.join(".")
19
19
  end
20
20
 
21
- RELEASE = "2.0.9.2"
21
+ RELEASE = "2.0.9.3"
22
22
 
23
23
  # Return the Rack release as a dotted string.
24
24
  def self.release
@@ -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.2
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-01-17 00:00:00.000000000 Z
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.6
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/spec_multipart.rb
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/spec_static.rb
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/spec_version.rb
298
+ - test/spec_events.rb
299
+ - test/spec_fastcgi.rb
300
+ - test/spec_file.rb
290
301
  - test/spec_handler.rb
291
- - test/spec_thin.rb
292
- - test/spec_session_abstract_id.rb
293
- - test/spec_mime.rb
294
- - test/spec_recursive.rb
295
- - test/spec_null_logger.rb
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/spec_content_type.rb
300
- - test/spec_session_abstract_session_hash.rb
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/spec_chunked.rb
303
- - test/spec_show_exceptions.rb
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/spec_directory.rb
319
- - test/spec_webrick.rb
320
- - test/spec_response.rb
321
- - test/spec_file.rb
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/spec_body_proxy.rb
324
- - test/spec_logger.rb
325
- - test/spec_auth_digest.rb
328
+ - test/spec_static.rb
329
+ - test/spec_tempfile_reaper.rb
330
+ - test/spec_thin.rb
326
331
  - test/spec_urlmap.rb
327
- - test/spec_events.rb
328
- - test/spec_cascade.rb
329
- - test/spec_auth_basic.rb
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