rack 2.2.3 → 2.2.6.4

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: 0b7c25cb392fb659dc54ab275c38e8d838c4357b046f59ff44698d6110129e85
4
- data.tar.gz: 1f8fbe6d0923969234e772409a98ed6e0a5f0d10efed6a76ac80902257a5bd90
3
+ metadata.gz: '078561a77beb0af3f12ba96b1a506598140482eec56592a6800e7bf14d5b57c9'
4
+ data.tar.gz: d14d73096818a28e4dc1e9e98309164029ba0c24768468c6299d11d11fe6a839
5
5
  SHA512:
6
- metadata.gz: 9021496ff7dce72833074adc1963a0cc5a96bfc14a162cc56d7c54441c3f17de61804f687943a0d07ebe58399c92db540d322576010b4e47c375cdd9aec7d09d
7
- data.tar.gz: b668e5359266b7ad36387bddd7db329968b5a38ef10290ef22da30e2f7edd082ffebc9e864cc44f09cfb51b491111d27ff1a55a3fa011ad3d45aa6374a8ccb3c
6
+ metadata.gz: 577296b45efdde2334fa386c57b6a9dcd8409cf8949875bcd78970041a078af1fa48e7cf030c6e4bf1377a7eecc771332aeec4c135df25ca74116ae56ab015de
7
+ data.tar.gz: f589a73eb2b74eea08499e4e945df139612619c1d6543edc0d8ebe78bb2b8181625464d607150a3ef89b86659f6a1bb1838a7940bd64bd418d2ac21873a067db
data/CHANGELOG.md CHANGED
@@ -2,8 +2,49 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. For info on how to format all future additions to this file please reference [Keep A Changelog](https://keepachangelog.com/en/1.0.0/).
4
4
 
5
+ ## [2.2.6.4] - 2023-03-13
6
+
7
+ - [CVE-2023-27539] Avoid ReDoS in header parsing
8
+
9
+ ## [2.2.6.3] - 2023-03-02
10
+
11
+ - [CVE-2023-27530] Introduce multipart_total_part_limit to limit total parts
12
+
13
+ ## [2.2.6.2] - 2022-01-17
14
+
15
+ - [CVE-2022-44570] Fix ReDoS in Rack::Utils.get_byte_ranges
16
+
17
+ ## [2.2.6.1] - 2022-01-17
18
+
19
+ - [CVE-2022-44571] Fix ReDoS vulnerability in multipart parser
20
+ - [CVE-2022-44572] Forbid control characters in attributes (also ReDoS)
21
+
22
+ ## [2.2.6] - 2022-01-17
23
+
24
+ - Extend `Rack::MethodOverride` to handle `QueryParser::ParamsTooDeepError` error. ([#2011](https://github.com/rack/rack/pull/2011), [@byroot](https://github.com/byroot))
25
+
26
+ ## [2.2.5] - 2022-12-27
27
+
28
+ ### Fixed
29
+
30
+ - `Rack::URLMap` uses non-deprecated form of `Regexp.new`. ([#1998](https://github.com/rack/rack/pull/1998), [@weizheheng](https://github.com/weizheheng))
31
+
32
+ ## [2.2.4] - 2022-06-30
33
+
34
+ - Better support for lower case headers in `Rack::ETag` middleware. ([#1919](https://github.com/rack/rack/pull/1919), [@ioquatix](https://github.com/ioquatix))
35
+ - Use custom exception on params too deep error. ([#1838](https://github.com/rack/rack/pull/1838), [@simi](https://github.com/simi))
36
+
37
+ ## [2.2.3.1] - 2022-05-27
38
+
39
+ ### Security
40
+
41
+ - [CVE-2022-30123] Fix shell escaping issue in Common Logger
42
+ - [CVE-2022-30122] Restrict parsing of broken MIME attachments
43
+
5
44
  ## [2.2.3] - 2020-02-11
6
45
 
46
+ ### Security
47
+
7
48
  - [CVE-2020-8184] Only decode cookie values
8
49
 
9
50
  ## [2.2.2] - 2020-02-11
data/README.rdoc CHANGED
@@ -202,16 +202,30 @@ Limiting the depth prevents a possible stack overflow when parsing parameters.
202
202
 
203
203
  Defaults to 100.
204
204
 
205
- === multipart_part_limit
205
+ === multipart_file_limit
206
206
 
207
- The maximum number of parts a request can contain.
207
+ The maximum number of parts with a filename a request can contain.
208
208
  Accepting too many part can lead to the server running out of file handles.
209
209
 
210
210
  The default is 128, which means that a single request can't upload more than 128 files at once.
211
211
 
212
212
  Set to 0 for no limit.
213
213
 
214
- Can also be set via the +RACK_MULTIPART_PART_LIMIT+ environment variable.
214
+ Can also be set via the +RACK_MULTIPART_FILE_LIMIT+ environment variable.
215
+
216
+ (This is also aliased as +multipart_part_limit+ and +RACK_MULTIPART_PART_LIMIT+ for compatibility)
217
+
218
+ === multipart_total_part_limit
219
+
220
+ The maximum total number of parts a request can contain of any type, including
221
+ both file and non-file form fields.
222
+
223
+ The default is 4096, which means that a single request can't contain more than
224
+ 4096 parts.
225
+
226
+ Set to 0 for no limit.
227
+
228
+ Can also be set via the +RACK_MULTIPART_TOTAL_PART_LIMIT+ environment variable.
215
229
 
216
230
  == Changelog
217
231
 
data/SPEC.rdoc CHANGED
@@ -42,18 +42,17 @@ below.
42
42
  <tt>QUERY_STRING</tt>:: The portion of the request URL that
43
43
  follows the <tt>?</tt>, if any. May be
44
44
  empty, but is always required!
45
- <tt>SERVER_NAME</tt>:: When combined with <tt>SCRIPT_NAME</tt> and
45
+ <tt>SERVER_NAME</tt>, <tt>SERVER_PORT</tt>::
46
+ When combined with <tt>SCRIPT_NAME</tt> and
46
47
  <tt>PATH_INFO</tt>, these variables can be
47
48
  used to complete the URL. Note, however,
48
49
  that <tt>HTTP_HOST</tt>, if present,
49
50
  should be used in preference to
50
51
  <tt>SERVER_NAME</tt> for reconstructing
51
52
  the request URL.
52
- <tt>SERVER_NAME</tt> can never be an empty
53
- string, and so is always required.
54
- <tt>SERVER_PORT</tt>:: An optional +Integer+ which is the port the
55
- server is running on. Should be specified if
56
- the server is running on a non-standard port.
53
+ <tt>SERVER_NAME</tt> and <tt>SERVER_PORT</tt>
54
+ can never be empty strings, and so
55
+ are always required.
57
56
  <tt>HTTP_</tt> Variables:: Variables corresponding to the
58
57
  client-supplied HTTP request
59
58
  headers (i.e., variables whose
@@ -123,9 +122,6 @@ and should be prefixed uniquely. The prefix <tt>rack.</tt>
123
122
  is reserved for use with the Rack core distribution and other
124
123
  accepted specifications and must not be used otherwise.
125
124
 
126
- The <tt>SERVER_PORT</tt> must be an Integer if set.
127
- The <tt>SERVER_NAME</tt> must be a valid authority as defined by RFC7540.
128
- The <tt>HTTP_HOST</tt> must be a valid authority as defined by RFC7540.
129
125
  The environment must not contain the keys
130
126
  <tt>HTTP_CONTENT_TYPE</tt> or <tt>HTTP_CONTENT_LENGTH</tt>
131
127
  (use the versions without <tt>HTTP_</tt>).
@@ -60,7 +60,10 @@ module Rack
60
60
  length,
61
61
  Utils.clock_time - began_at ]
62
62
 
63
+ msg.gsub!(/[^[:print:]\n]/) { |c| "\\x#{c.ord}" }
64
+
63
65
  logger = @logger || env[RACK_ERRORS]
66
+
64
67
  # Standard library logger doesn't support write but it supports << which actually
65
68
  # calls to write on the log device without formatting
66
69
  if logger.respond_to?(:write)
data/lib/rack/etag.rb CHANGED
@@ -26,6 +26,8 @@ module Rack
26
26
  def call(env)
27
27
  status, headers, body = @app.call(env)
28
28
 
29
+ headers = Utils::HeaderHash[headers]
30
+
29
31
  if etag_status?(status) && etag_body?(body) && !skip_caching?(headers)
30
32
  original_body = body
31
33
  digest, new_body = digest_body(body)
data/lib/rack/lint.rb CHANGED
@@ -48,10 +48,10 @@ module Rack
48
48
 
49
49
  ## and returns an Array of exactly three values:
50
50
  ary = @app.call(env)
51
- assert("response #{ary.inspect} is not an Array , but #{ary.class}") {
51
+ assert("response is not an Array, but #{ary.class}") {
52
52
  ary.kind_of? Array
53
53
  }
54
- assert("response array #{ary.inspect} has #{ary.size} elements instead of 3") {
54
+ assert("response array has #{ary.size} elements instead of 3") {
55
55
  ary.size == 3
56
56
  }
57
57
 
@@ -337,7 +337,7 @@ module Rack
337
337
  check_hijack env
338
338
 
339
339
  ## * The <tt>REQUEST_METHOD</tt> must be a valid token.
340
- assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD]}") {
340
+ assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD].dump}") {
341
341
  env[REQUEST_METHOD] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/
342
342
  }
343
343
 
@@ -43,7 +43,7 @@ module Rack
43
43
 
44
44
  def method_override_param(req)
45
45
  req.POST[METHOD_OVERRIDE_PARAM_KEY]
46
- rescue Utils::InvalidParameterError, Utils::ParameterTypeError
46
+ rescue Utils::InvalidParameterError, Utils::ParameterTypeError, QueryParser::ParamsTooDeepError
47
47
  req.get_header(RACK_ERRORS).puts "Invalid or incomplete POST params"
48
48
  rescue EOFError
49
49
  req.get_header(RACK_ERRORS).puts "Bad request content body"
@@ -5,6 +5,7 @@ require 'strscan'
5
5
  module Rack
6
6
  module Multipart
7
7
  class MultipartPartLimitError < Errno::EMFILE; end
8
+ class MultipartTotalPartLimitError < StandardError; end
8
9
 
9
10
  class Parser
10
11
  (require_relative '../core_ext/regexp'; using ::Rack::RegexpExtensions) if RUBY_VERSION < '2.4'
@@ -140,7 +141,7 @@ module Rack
140
141
 
141
142
  @mime_parts[mime_index] = klass.new(body, head, filename, content_type, name)
142
143
 
143
- check_open_files
144
+ check_part_limits
144
145
  end
145
146
 
146
147
  def on_mime_body(mime_index, content)
@@ -152,13 +153,23 @@ module Rack
152
153
 
153
154
  private
154
155
 
155
- def check_open_files
156
- if Utils.multipart_part_limit > 0
157
- if @open_files >= Utils.multipart_part_limit
156
+ def check_part_limits
157
+ file_limit = Utils.multipart_file_limit
158
+ part_limit = Utils.multipart_total_part_limit
159
+
160
+ if file_limit && file_limit > 0
161
+ if @open_files >= file_limit
158
162
  @mime_parts.each(&:close)
159
163
  raise MultipartPartLimitError, 'Maximum file multiparts in content reached'
160
164
  end
161
165
  end
166
+
167
+ if part_limit && part_limit > 0
168
+ if @mime_parts.size >= part_limit
169
+ @mime_parts.each(&:close)
170
+ raise MultipartTotalPartLimitError, 'Maximum total multiparts in content reached'
171
+ end
172
+ end
162
173
  end
163
174
  end
164
175
 
@@ -301,8 +312,9 @@ module Rack
301
312
  elsif filename = params['filename*']
302
313
  encoding, _, filename = filename.split("'", 3)
303
314
  end
304
- when BROKEN_QUOTED, BROKEN_UNQUOTED
315
+ when BROKEN
305
316
  filename = $1
317
+ filename = $1 if filename =~ /^"(.*)"$/
306
318
  end
307
319
 
308
320
  return unless filename
@@ -16,13 +16,12 @@ module Rack
16
16
  TOKEN = /[^\s()<>,;:\\"\/\[\]?=]+/
17
17
  CONDISP = /Content-Disposition:\s*#{TOKEN}\s*/i
18
18
  VALUE = /"(?:\\"|[^"])*"|#{TOKEN}/
19
- BROKEN_QUOTED = /^#{CONDISP}.*;\s*filename="(.*?)"(?:\s*$|\s*;\s*#{TOKEN}=)/i
20
- BROKEN_UNQUOTED = /^#{CONDISP}.*;\s*filename=(#{TOKEN})/i
19
+ BROKEN = /^#{CONDISP}.*;\s*filename=(#{VALUE})/i
21
20
  MULTIPART_CONTENT_TYPE = /Content-Type: (.*)#{EOL}/ni
22
- MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:.*;\s*name=(#{VALUE})/ni
21
+ MULTIPART_CONTENT_DISPOSITION = /Content-Disposition:[^:]*;\s*name=(#{VALUE})/ni
23
22
  MULTIPART_CONTENT_ID = /Content-ID:\s*([^#{EOL}]*)/ni
24
23
  # Updated definitions from RFC 2231
25
- ATTRIBUTE_CHAR = %r{[^ \t\v\n\r)(><@,;:\\"/\[\]?='*%]}
24
+ ATTRIBUTE_CHAR = %r{[^ \x00-\x1f\x7f)(><@,;:\\"/\[\]?='*%]}
26
25
  ATTRIBUTE = /#{ATTRIBUTE_CHAR}+/
27
26
  SECTION = /\*[0-9]+/
28
27
  REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
@@ -16,6 +16,10 @@ module Rack
16
16
  # sequence.
17
17
  class InvalidParameterError < ArgumentError; end
18
18
 
19
+ # ParamsTooDeepError is the error that is raised when params are recursively
20
+ # nested over the specified limit.
21
+ class ParamsTooDeepError < RangeError; end
22
+
19
23
  def self.make_default(key_space_limit, param_depth_limit)
20
24
  new Params, key_space_limit, param_depth_limit
21
25
  end
@@ -81,7 +85,7 @@ module Rack
81
85
  # the structural types represented by two different parameter names are in
82
86
  # conflict, a ParameterTypeError is raised.
83
87
  def normalize_params(params, name, v, depth)
84
- raise RangeError if depth <= 0
88
+ raise ParamsTooDeepError if depth <= 0
85
89
 
86
90
  name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
87
91
  k = $1 || ''
@@ -168,7 +172,7 @@ module Rack
168
172
 
169
173
  def []=(key, value)
170
174
  @size += key.size if key && !@params.key?(key)
171
- raise RangeError, 'exceeded available parameter key space' if @size > @limit
175
+ raise ParamsTooDeepError, 'exceeded available parameter key space' if @size > @limit
172
176
  @params[key] = value
173
177
  end
174
178
 
data/lib/rack/request.rb CHANGED
@@ -572,8 +572,8 @@ module Rack
572
572
  end
573
573
 
574
574
  def parse_http_accept_header(header)
575
- header.to_s.split(/\s*,\s*/).map do |part|
576
- attribute, parameters = part.split(/\s*;\s*/, 2)
575
+ header.to_s.split(",").each(&:strip!).map do |part|
576
+ attribute, parameters = part.split(";", 2).each(&:strip!)
577
577
  quality = 1.0
578
578
  if parameters and /\Aq=([\d.]+)/ =~ parameters
579
579
  quality = $1.to_f
data/lib/rack/urlmap.rb CHANGED
@@ -35,7 +35,7 @@ module Rack
35
35
  end
36
36
 
37
37
  location = location.chomp('/')
38
- match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')
38
+ match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", Regexp::NOENCODING)
39
39
 
40
40
  [host, location, match, app]
41
41
  }.sort_by do |(host, location, _, _)|
data/lib/rack/utils.rb CHANGED
@@ -22,6 +22,9 @@ module Rack
22
22
  COMMON_SEP = QueryParser::COMMON_SEP
23
23
  KeySpaceConstrainedParams = QueryParser::Params
24
24
 
25
+ RFC2822_DAY_NAME = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]
26
+ RFC2822_MONTH_NAME = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
27
+
25
28
  class << self
26
29
  attr_accessor :default_query_parser
27
30
  end
@@ -55,13 +58,24 @@ module Rack
55
58
  end
56
59
 
57
60
  class << self
58
- attr_accessor :multipart_part_limit
61
+ attr_accessor :multipart_total_part_limit
62
+
63
+ attr_accessor :multipart_file_limit
64
+
65
+ # multipart_part_limit is the original name of multipart_file_limit, but
66
+ # the limit only counts parts with filenames.
67
+ alias multipart_part_limit multipart_file_limit
68
+ alias multipart_part_limit= multipart_file_limit=
59
69
  end
60
70
 
61
- # The maximum number of parts a request can contain. Accepting too many part
62
- # can lead to the server running out of file handles.
71
+ # The maximum number of file parts a request can contain. Accepting too
72
+ # many parts can lead to the server running out of file handles.
63
73
  # Set to `0` for no limit.
64
- self.multipart_part_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || 128).to_i
74
+ self.multipart_file_limit = (ENV['RACK_MULTIPART_PART_LIMIT'] || ENV['RACK_MULTIPART_FILE_LIMIT'] || 128).to_i
75
+
76
+ # The maximum total number of parts a request can contain. Accepting too
77
+ # many can lead to excessive memory use and parsing time.
78
+ self.multipart_total_part_limit = (ENV['RACK_MULTIPART_TOTAL_PART_LIMIT'] || 4096).to_i
65
79
 
66
80
  def self.param_depth_limit
67
81
  default_query_parser.param_depth_limit
@@ -327,8 +341,8 @@ module Rack
327
341
  # weekday and month.
328
342
  #
329
343
  def rfc2109(time)
330
- wday = Time::RFC2822_DAY_NAME[time.wday]
331
- mon = Time::RFC2822_MONTH_NAME[time.mon - 1]
344
+ wday = RFC2822_DAY_NAME[time.wday]
345
+ mon = RFC2822_MONTH_NAME[time.mon - 1]
332
346
  time.strftime("#{wday}, %d-#{mon}-%Y %H:%M:%S GMT")
333
347
  end
334
348
 
@@ -345,17 +359,18 @@ module Rack
345
359
  return nil unless http_range && http_range =~ /bytes=([^;]+)/
346
360
  ranges = []
347
361
  $1.split(/,\s*/).each do |range_spec|
348
- return nil unless range_spec =~ /(\d*)-(\d*)/
349
- r0, r1 = $1, $2
350
- if r0.empty?
351
- return nil if r1.empty?
362
+ return nil unless range_spec.include?('-')
363
+ range = range_spec.split('-')
364
+ r0, r1 = range[0], range[1]
365
+ if r0.nil? || r0.empty?
366
+ return nil if r1.nil?
352
367
  # suffix-byte-range-spec, represents trailing suffix of file
353
368
  r0 = size - r1.to_i
354
369
  r0 = 0 if r0 < 0
355
370
  r1 = size - 1
356
371
  else
357
372
  r0 = r0.to_i
358
- if r1.empty?
373
+ if r1.nil?
359
374
  r1 = size - 1
360
375
  else
361
376
  r1 = r1.to_i
data/lib/rack/version.rb CHANGED
@@ -20,7 +20,7 @@ module Rack
20
20
  VERSION.join(".")
21
21
  end
22
22
 
23
- RELEASE = "2.2.3"
23
+ RELEASE = "2.2.6.4"
24
24
 
25
25
  # Return the Rack release as a dotted string.
26
26
  def self.release
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.2.3
4
+ version: 2.2.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Neukirchen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-15 00:00:00.000000000 Z
11
+ date: 2023-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -169,7 +169,7 @@ metadata:
169
169
  changelog_uri: https://github.com/rack/rack/blob/master/CHANGELOG.md
170
170
  documentation_uri: https://rubydoc.info/github/rack/rack
171
171
  source_code_uri: https://github.com/rack/rack
172
- post_install_message:
172
+ post_install_message:
173
173
  rdoc_options: []
174
174
  require_paths:
175
175
  - lib
@@ -184,8 +184,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
184
  - !ruby/object:Gem::Version
185
185
  version: '0'
186
186
  requirements: []
187
- rubygems_version: 3.2.0.pre1
188
- signing_key:
187
+ rubygems_version: 3.0.3.1
188
+ signing_key:
189
189
  specification_version: 4
190
190
  summary: A modular Ruby webserver interface.
191
191
  test_files: []