File CVE-2019-16770.patch of Package rubygem-puma.16022
From 62969a4cdc741fbcb8455204772ffd9a11876cc6 Mon Sep 17 00:00:00 2001
From: Nate Berkopec <nate.berkopec@gmail.com>
Date: Thu, 5 Dec 2019 14:19:32 +0700
Subject: [PATCH] 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>
---
lib/puma/const.rb | 7 +++++++
lib/puma/server.rb | 16 +++++++++++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/lib/puma/const.rb b/lib/puma/const.rb
index 3597bb03..a2c5be05 100644
--- a/lib/puma/const.rb
+++ b/lib/puma/const.rb
@@ -116,6 +116,13 @@ module Puma
# sending data back
WRITE_TIMEOUT = 10
+ # 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 fe5eb070..293342c1 100644
--- a/lib/puma/server.rb
+++ b/lib/puma/server.rb
@@ -442,6 +442,8 @@ module Puma
clean_thread_locals = @options[:clean_thread_locals]
close_socket = true
+ requests = 0
+
while true
case handle_request(client, buffer)
when false
@@ -455,7 +457,19 @@ module Puma
ThreadPool.clean_thread_locals if clean_thread_locals
- 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
--
2.26.2