From c6340d1fabcd02c4cc5c1d4effaeba393dedb1a8 Mon Sep 17 00:00:00 2001 From: Nate Berkopec Date: Fri, 11 Feb 2022 14:06:43 -0700 Subject: [PATCH] 5.6.2 (#2821) * Ensure `close` is called on the response body no matter what Another fallout from https://github.com/puma/puma/pull/2809 is that in some cases the `res_body.close` wasn't called because some previous code raised. For Rails apps it means CurrentAttributes and a few other important states aren't reset properly. This is being improved on the Rails side too, but I believe it would be good to harden this on the puma side as well. * 5.6.2 Co-authored-by: Jean Boussier --- History.md | 5 +++++ lib/puma/const.rb | 2 +- lib/puma/request.rb | 15 ++++++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/History.md b/History.md index f85aa2883e..7c1cd93c77 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +## 5.6.2 / 2022-02-11 + +* Bugfix/Security + * Response body will always be `close`d. (GHSA-rmj8-8hhh-gv5h, related to [#2809]) + ## 5.6.1 / 2022-01-26 * Bugfixes diff --git a/lib/puma/const.rb b/lib/puma/const.rb index 42e8f2241b..eaa6dfb6a4 100644 --- a/lib/puma/const.rb +++ b/lib/puma/const.rb @@ -100,7 +100,7 @@ class UnsupportedOption < RuntimeError # too taxing on performance. module Const - PUMA_VERSION = VERSION = "5.6.1".freeze + PUMA_VERSION = VERSION = "5.6.2".freeze CODE_NAME = "Birdie's Version".freeze PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze diff --git a/lib/puma/request.rb b/lib/puma/request.rb index 948992895f..698cea68de 100644 --- a/lib/puma/request.rb +++ b/lib/puma/request.rb @@ -167,11 +167,16 @@ def handle_request(client, lines, requests) end ensure - uncork_socket io - - body.close - client.tempfile.unlink if client.tempfile - res_body.close if res_body.respond_to? :close + begin + uncork_socket io + + body.close + client.tempfile.unlink if client.tempfile + ensure + # Whatever happens, we MUST call `close` on the response body. + # Otherwise Rack::BodyProxy callbacks may not fire and lead to various state leaks + res_body.close if res_body.respond_to? :close + end after_reply.each { |o| o.call } end