diff options
author | John Hawthorn <john@hawthorn.email> | 2023-01-17 16:33:47 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-17 16:33:47 -0800 |
commit | ffff364d8154af8d0abeafce9ebe4b5c4eade11c (patch) | |
tree | cd55be8172b4a06d7f331d8ba3fa145c1cb89491 | |
parent | becbf4b11245918cd3d91b9ac390a8ea8cd58f3c (diff) | |
download | rack-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.rb | 2 |
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}*/ |