File CVE-2019-16770.patch of Package rubygem-puma.15815
commit 5481c73aac215432bd09451d02985b3f89eec85c
Author: Nate Berkopec <nate.berkopec@gmail.com>
Date: Thu Dec 5 14:19:32 2019 +0700
Merge pull request from GHSA-7xx3-m584-x994
could monopolize a thread. Previously, this could make a DoS attack more
severe.
Co-authored-by: Evan Phoenix <evan@phx.io>
(cherry picked from commit 06053e60908074bb38293d4449ea261cb009b53e)
diff --git a/lib/puma/const.rb b/lib/puma/const.rb
index d63d145db07c..f302dfd32b14 100644
--- a/lib/puma/const.rb
+++ b/lib/puma/const.rb
@@ -120,6 +120,13 @@ module Puma
SCRIPT_NAME = "SCRIPT_NAME".freeze
+ # How many requests to attempt inline before sending a client back to
+ # the reactor to be subject to normal ordering. The idea here is that
+ # we amortize the cost of going back to the reactor for a well behaved
+ # but very "greedy" client across 10 requests. This prevents a not
+ # well behaved client from monopolizing the thread forever.
+ MAX_FAST_INLINE = 10
+
# The original URI requested by the client.
REQUEST_URI= 'REQUEST_URI'.freeze
REQUEST_PATH = 'REQUEST_PATH'.freeze
diff --git a/lib/puma/server.rb b/lib/puma/server.rb
index 7ebe0eedfe7a..f6aa7e0024d1 100644
--- a/lib/puma/server.rb
+++ b/lib/puma/server.rb
@@ -400,6 +400,8 @@ module Puma
begin
close_socket = true
+ requests = 0
+
while true
case handle_request(client, buffer)
when false
@@ -411,7 +413,19 @@ module Puma
return unless @queue_requests
buffer.reset
- unless client.reset(@status == :run)
+ requests += 1
+
+ check_for_more_data = @status == :run
+
+ if requests >= MAX_FAST_INLINE
+ # This will mean that reset will only try to use the data it already
+ # has buffered and won't try to read more data. What this means is that
+ # every client, independent of their request speed, gets treated like a slow
+ # one once every MAX_FAST_INLINE requests.
+ check_for_more_data = false
+ end
+
+ unless client.reset(check_for_more_data)
close_socket = false
client.set_timeout @persistent_timeout
@reactor.add client