summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <john@hawthorn.email>2023-01-17 16:33:47 -0800
committerGitHub <noreply@github.com>2023-01-17 16:33:47 -0800
commitffff364d8154af8d0abeafce9ebe4b5c4eade11c (patch)
treecd55be8172b4a06d7f331d8ba3fa145c1cb89491
parentbecbf4b11245918cd3d91b9ac390a8ea8cd58f3c (diff)
downloadrack-ffff364d8154af8d0abeafce9ebe4b5c4eade11c.tar.gz
Make RFC2183 work with Ruby 3.2's caching Regexp (#2014)
Ruby 3.2 includes a cache-based regexp optimization, which is detailed in https://bugs.ruby-lang.org/issues/19104. Which can speed up the regex engine on many cases which would previously have resulted in a ReDoS. One caveat of the implmentation is (quoting the issue): > A bounded or fixed times repetition nesting in another repetition > (e.g. /(a{2,3})*/). It is an implementation issue entirely, but we > believe it is hard to support this case correctly. Because of that limitation the RFC2183 regex was not previously able to use that optimization and was not able to mitigate two recent ReDoS CVEs. This commit manually expands a `{2}` fixed repetition, which allows Ruby 3.2's optimization to take effect. Before: > Regexp.linear_time?(/([0-9]{2})*/) => false > Regexp.linear_time?(Rack::Multipart::RFC2183) => false After: > Regexp.linear_time?(/([0-9][0-9])*/) => true > Regexp.linear_time?(Rack::Multipart::RFC2183) => true I want to make this change as additional hardening against possible ReDoS attacks in this regex. At the moment I don't know of any which are unpatched.
-rw-r--r--lib/rack/multipart/parser.rb2
1 files changed, 1 insertions, 1 deletions
diff --git a/lib/rack/multipart/parser.rb b/lib/rack/multipart/parser.rb
index d5a3c8dd..ceafbc6b 100644
--- a/lib/rack/multipart/parser.rb
+++ b/lib/rack/multipart/parser.rb
@@ -32,7 +32,7 @@ module Rack
REGULAR_PARAMETER_NAME = /#{ATTRIBUTE}#{SECTION}?/
REGULAR_PARAMETER = /(#{REGULAR_PARAMETER_NAME})=(#{VALUE})/
EXTENDED_OTHER_NAME = /#{ATTRIBUTE}\*[1-9][0-9]*\*/
- EXTENDED_OTHER_VALUE = /%[0-9a-fA-F]{2}|#{ATTRIBUTE_CHAR}/
+ EXTENDED_OTHER_VALUE = /%[0-9a-fA-F][0-9a-fA-F]|#{ATTRIBUTE_CHAR}/
EXTENDED_OTHER_PARAMETER = /(#{EXTENDED_OTHER_NAME})=(#{EXTENDED_OTHER_VALUE}*)/
EXTENDED_INITIAL_NAME = /#{ATTRIBUTE}(?:\*0)?\*/
EXTENDED_INITIAL_VALUE = /[a-zA-Z0-9\-]*'[a-zA-Z0-9\-]*'#{EXTENDED_OTHER_VALUE}*/