diff --git a/CVE-2022-23634.patch b/CVE-2022-23634.patch deleted file mode 100644 index 3a97180512957d7aecc50fcc20b280f2895456be..0000000000000000000000000000000000000000 --- a/CVE-2022-23634.patch +++ /dev/null @@ -1,44 +0,0 @@ -From b70f451fe8abc0cff192c065d549778452e155bb Mon Sep 17 00:00:00 2001 -From: Jean Boussier -Date: Fri, 11 Feb 2022 15:58:08 +0100 -Subject: [PATCH] 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. ---- - lib/puma/request.rb | 15 ++++++++++----- - 1 file changed, 10 insertions(+), 5 deletions(-) - -diff --git a/lib/puma/request.rb b/lib/puma/request.rb -index 10508c8d44..691ada424f 100644 ---- a/lib/puma/request.rb -+++ b/lib/puma/request.rb -@@ -171,11 +171,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 diff --git a/CVE-2023-40175.patch b/CVE-2023-40175.patch new file mode 100644 index 0000000000000000000000000000000000000000..c3f4983116fd00d21880628c6509d24c88420ed9 --- /dev/null +++ b/CVE-2023-40175.patch @@ -0,0 +1,146 @@ +From 7405a219801dcebc0ad6e0aa108d4319ca23f662 Mon Sep 17 00:00:00 2001 +From: Nate Berkopec +Date: Fri, 18 Aug 2023 09:47:23 +0900 +Subject: [PATCH] Merge pull request from GHSA-68xg-gqqm-vgj8 + +Origin: https://github.com/puma/puma/commit/7405a219801dcebc0ad6e0aa108d4319ca23f662 + +* Reject empty string for Content-Length + +* Ignore trailers in last chunk + +* test_puma_server.rb - use heredoc, test_cl_and_te_smuggle + +* client.rb - stye/RubyCop + +* test_puma_server.rb - indented heredoc rubocop disable + +* Dentarg comments + +* Remove unused variable + +--------- + +Co-authored-by: MSP-Greg +--- + lib/puma/client.rb | 23 ++++++++++++++-------- + test/test_puma_server.rb | 42 +++++++++++++++++++++++++++++++++++++++- + 2 files changed, 56 insertions(+), 9 deletions(-) + +diff --git a/lib/puma/client.rb b/lib/puma/client.rb +index e966f995e8..9c11912caa 100644 +--- a/lib/puma/client.rb ++++ b/lib/puma/client.rb +@@ -45,7 +45,8 @@ class Client + + # chunked body validation + CHUNK_SIZE_INVALID = /[^\h]/.freeze +- CHUNK_VALID_ENDING = "\r\n".freeze ++ CHUNK_VALID_ENDING = Const::LINE_END ++ CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize + + # Content-Length header value validation + CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze +@@ -347,8 +348,8 @@ def setup_body + cl = @env[CONTENT_LENGTH] + + if cl +- # cannot contain characters that are not \d +- if cl =~ CONTENT_LENGTH_VALUE_INVALID ++ # cannot contain characters that are not \d, or be empty ++ if cl =~ CONTENT_LENGTH_VALUE_INVALID || cl.empty? + raise HttpParserError, "Invalid Content-Length: #{cl.inspect}" + end + else +@@ -509,7 +510,7 @@ def decode_chunk(chunk) + + while !io.eof? + line = io.gets +- if line.end_with?("\r\n") ++ if line.end_with?(CHUNK_VALID_ENDING) + # Puma doesn't process chunk extensions, but should parse if they're + # present, which is the reason for the semicolon regex + chunk_hex = line.strip[/\A[^;]+/] +@@ -521,13 +522,19 @@ def decode_chunk(chunk) + @in_last_chunk = true + @body.rewind + rest = io.read +- last_crlf_size = "\r\n".bytesize +- if rest.bytesize < last_crlf_size ++ if rest.bytesize < CHUNK_VALID_ENDING_SIZE + @buffer = nil +- @partial_part_left = last_crlf_size - rest.bytesize ++ @partial_part_left = CHUNK_VALID_ENDING_SIZE - rest.bytesize + return false + else +- @buffer = rest[last_crlf_size..-1] ++ # if the next character is a CRLF, set buffer to everything after that CRLF ++ start_of_rest = if rest.start_with?(CHUNK_VALID_ENDING) ++ CHUNK_VALID_ENDING_SIZE ++ else # we have started a trailer section, which we do not support. skip it! ++ rest.index(CHUNK_VALID_ENDING*2) + CHUNK_VALID_ENDING_SIZE*2 ++ end ++ ++ @buffer = rest[start_of_rest..-1] + @buffer = nil if @buffer.empty? + set_ready + return true +diff --git a/test/test_puma_server.rb b/test/test_puma_server.rb +index 298e44b439..2bfaf98848 100644 +--- a/test/test_puma_server.rb ++++ b/test/test_puma_server.rb +@@ -627,7 +627,7 @@ def test_large_chunked_request + [200, {}, [""]] + } + +- header = "GET / HTTP/1.1\r\nConnection: close\r\nTransfer-Encoding: chunked\r\n\r\n" ++ header = "GET / HTTP/1.1\r\nConnection: close\r\nContent-Length: 200\r\nTransfer-Encoding: chunked\r\n\r\n" + + chunk_header_size = 6 # 4fb8\r\n + # Current implementation reads one chunk of CHUNK_SIZE, then more chunks of size 4096. +@@ -1365,4 +1365,44 @@ def test_rack_url_scheme_user + data = send_http_and_read "GET / HTTP/1.0\r\n\r\n" + assert_equal "user", data.split("\r\n").last + end ++ ++ def test_cl_empty_string ++ server_run do |env| ++ [200, {}, [""]] ++ end ++ ++ empty_cl_request = "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length:\r\n\r\nGET / HTTP/1.1\r\nHost: localhost\r\n\r\n" ++ ++ data = send_http_and_read empty_cl_request ++ assert_operator data, :start_with?, 'HTTP/1.1 400 Bad Request' ++ end ++ ++ def test_crlf_trailer_smuggle ++ server_run do |env| ++ [200, {}, [""]] ++ end ++ ++ smuggled_payload = "GET / HTTP/1.1\r\nTransfer-Encoding: chunked\r\nHost: whatever\r\n\r\n0\r\nX:POST / HTTP/1.1\r\nHost: whatever\r\n\r\nGET / HTTP/1.1\r\nHost: whatever\r\n\r\n" ++ ++ data = send_http_and_read smuggled_payload ++ assert_equal 2, data.scan("HTTP/1.1 200 OK").size ++ end ++ ++ # test to check if content-length is ignored when 'transfer-encoding: chunked' ++ # is used. See also test_large_chunked_request ++ def test_cl_and_te_smuggle ++ body = nil ++ server_run { |env| ++ body = env['rack.input'].read ++ [200, {}, [""]] ++ } ++ ++ req = "POST /search HTTP/1.1\r\nHost: vulnerable-website.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 4\r\nTransfer-Encoding: chunked\r\n\r\n7b\r\nGET /404 HTTP/1.1\r\nHost: vulnerable-website.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 144\r\n\r\nx=\r\n0\r\n\r\n" ++ ++ data = send_http_and_read req ++ ++ assert_includes body, "GET /404 HTTP/1.1\r\n" ++ assert_includes body, "Content-Length: 144\r\n" ++ assert_equal 1, data.scan("HTTP/1.1 200 OK").size ++ end + end + diff --git a/CVE-2024-21647.patch b/CVE-2024-21647.patch index 7925db041ecd424027ee086f1150b46536e31b45..657b1da6fa89355c1c0f1bf1abeee0bd58d8cc0f 100644 --- a/CVE-2024-21647.patch +++ b/CVE-2024-21647.patch @@ -1,3 +1,6 @@ +Ubuntu note: simplified test case as to not hit this upstream bug: +https://github.com/puma/puma/issues/3307 + From bbb880ffb6debbfdea535b4b3eb2204d49ae151d Mon Sep 17 00:00:00 2001 From: Nate Berkopec Date: Mon, 8 Jan 2024 14:48:43 +0900 @@ -8,19 +11,18 @@ Origin: https://github.com/puma/puma/commit/bbb880ffb6debbfdea535b4b3eb2204d49ae Co-authored-by: MSP-Greg Co-authored-by: Patrik Ragnarsson Co-authored-by: Evan Phoenix - --- lib/puma/client.rb | 27 +++++++++++++++++++++++++++ test/test_puma_server.rb | 14 ++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/lib/puma/client.rb b/lib/puma/client.rb -index 0741107..9746bd4 100644 +index 9c11912caa..b5a1569c68 100644 --- a/lib/puma/client.rb +++ b/lib/puma/client.rb -@@ -40,6 +40,14 @@ module Puma - # no body share this one object since it has no state. - EmptyBody = NullIO.new +@@ -48,6 +48,14 @@ class Client + CHUNK_VALID_ENDING = Const::LINE_END + CHUNK_VALID_ENDING_SIZE = CHUNK_VALID_ENDING.bytesize + # The maximum number of bytes we'll buffer looking for a valid + # chunk header. @@ -30,10 +32,10 @@ index 0741107..9746bd4 100644 + # using chunk size extensions before we abort the connection. + MAX_CHUNK_EXCESS = 16 * 1024 + - include Puma::Const - extend Forwardable + # Content-Length header value validation + CONTENT_LENGTH_VALUE_INVALID = /[^\d]/.freeze -@@ -427,6 +435,7 @@ module Puma +@@ -460,6 +468,7 @@ def setup_chunked_body(body) @chunked_body = true @partial_part_left = 0 @prev_chunk = "" @@ -41,7 +43,7 @@ index 0741107..9746bd4 100644 @body = Tempfile.new(Const::PUMA_TMP_BASE) @body.unlink -@@ -496,6 +505,20 @@ module Puma +@@ -541,6 +550,20 @@ def decode_chunk(chunk) end end @@ -62,7 +64,7 @@ index 0741107..9746bd4 100644 len += 2 part = io.read(len) -@@ -518,6 +541,10 @@ module Puma +@@ -568,6 +591,10 @@ def decode_chunk(chunk) @partial_part_left = len - part.size end else @@ -74,10 +76,10 @@ index 0741107..9746bd4 100644 return false end diff --git a/test/test_puma_server.rb b/test/test_puma_server.rb -index bfa2b97..f179757 100644 +index 2bfaf98848..05bf83e20d 100644 --- a/test/test_puma_server.rb +++ b/test/test_puma_server.rb -@@ -645,6 +645,20 @@ EOF +@@ -648,6 +648,20 @@ def test_large_chunked_request end end @@ -92,7 +94,7 @@ index bfa2b97..f179757 100644 + + data = socket.read + -+ assert_match "HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", data ++ assert_match "HTTP/1.1 400 Bad Request\r\n\r\n", data + end + def test_chunked_request_pause_before_value diff --git a/Support-for-cert_pem-and-key_pem-with-ssl_bind-DSL.patch b/Support-for-cert_pem-and-key_pem-with-ssl_bind-DSL.patch deleted file mode 100644 index 8caca1f5cd550987cb5d39e3e8a1c7b241155e76..0000000000000000000000000000000000000000 --- a/Support-for-cert_pem-and-key_pem-with-ssl_bind-DSL.patch +++ /dev/null @@ -1,559 +0,0 @@ -From 5608248c13130740ca94697b63a59245140e8092 Mon Sep 17 00:00:00 2001 -From: Dalibor Nasevic -Date: Sun, 31 Oct 2021 14:59:21 +0100 -Subject: [PATCH] Support for cert_pem and key_pem with ssl_bind DSL (#2728) - -* Fix deprecation warning - -DEPRECATED: Use assert_nil if expecting nil from test/test_binder.rb:265. This will fail in Minitest 6. - -* Extend MiniSSL with support for cert_pem and key_pem - -* Extend Puma ssl_bind DSL with support for cert_pem and cert_key - -* Make some variables in binder test more readable ---- - ext/puma_http11/mini_ssl.c | 38 ++++++++-- - lib/puma/binder.rb | 13 +++- - lib/puma/dsl.rb | 29 ++++++++ - lib/puma/minissl.rb | 20 +++++- - lib/puma/minissl/context_builder.rb | 14 ++-- - test/test_binder.rb | 14 ++-- - test/test_config.rb | 22 ++++++ - test/test_integration_ssl.rb | 105 ++++++++++++++++++---------- - test/test_minissl.rb | 14 ++++ - test/test_puma_server_ssl.rb | 41 +++++++++++ - 10 files changed, 253 insertions(+), 57 deletions(-) - -diff --git a/ext/puma_http11/mini_ssl.c b/ext/puma_http11/mini_ssl.c -index 04bd1462d..6974b6349 100644 ---- a/ext/puma_http11/mini_ssl.c -+++ b/ext/puma_http11/mini_ssl.c -@@ -208,8 +208,11 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { - #endif - int ssl_options; - VALUE key, cert, ca, verify_mode, ssl_cipher_filter, no_tlsv1, no_tlsv1_1, -- verification_flags, session_id_bytes; -+ verification_flags, session_id_bytes, cert_pem, key_pem; - DH *dh; -+ BIO *bio; -+ X509 *x509; -+ EVP_PKEY *pkey; - - #if OPENSSL_VERSION_NUMBER < 0x10002000L - EC_KEY *ecdh; -@@ -218,13 +221,15 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { - TypedData_Get_Struct(self, SSL_CTX, &sslctx_type, ctx); - - key = rb_funcall(mini_ssl_ctx, rb_intern_const("key"), 0); -- StringValue(key); - - cert = rb_funcall(mini_ssl_ctx, rb_intern_const("cert"), 0); -- StringValue(cert); - - ca = rb_funcall(mini_ssl_ctx, rb_intern_const("ca"), 0); - -+ cert_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("cert_pem"), 0); -+ -+ key_pem = rb_funcall(mini_ssl_ctx, rb_intern_const("key_pem"), 0); -+ - verify_mode = rb_funcall(mini_ssl_ctx, rb_intern_const("verify_mode"), 0); - - ssl_cipher_filter = rb_funcall(mini_ssl_ctx, rb_intern_const("ssl_cipher_filter"), 0); -@@ -233,8 +238,31 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { - - no_tlsv1_1 = rb_funcall(mini_ssl_ctx, rb_intern_const("no_tlsv1_1"), 0); - -- SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)); -- SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM); -+ if (!NIL_P(cert)) { -+ StringValue(cert); -+ SSL_CTX_use_certificate_chain_file(ctx, RSTRING_PTR(cert)); -+ } -+ -+ if (!NIL_P(key)) { -+ StringValue(key); -+ SSL_CTX_use_PrivateKey_file(ctx, RSTRING_PTR(key), SSL_FILETYPE_PEM); -+ } -+ -+ if (!NIL_P(cert_pem)) { -+ bio = BIO_new(BIO_s_mem()); -+ BIO_puts(bio, RSTRING_PTR(cert_pem)); -+ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); -+ -+ SSL_CTX_use_certificate(ctx, x509); -+ } -+ -+ if (!NIL_P(key_pem)) { -+ bio = BIO_new(BIO_s_mem()); -+ BIO_puts(bio, RSTRING_PTR(key_pem)); -+ pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); -+ -+ SSL_CTX_use_PrivateKey(ctx, pkey); -+ } - - verification_flags = rb_funcall(mini_ssl_ctx, rb_intern_const("verification_flags"), 0); - -diff --git a/lib/puma/binder.rb b/lib/puma/binder.rb -index 6151889e7..3d688296b 100644 ---- a/lib/puma/binder.rb -+++ b/lib/puma/binder.rb -@@ -30,6 +30,7 @@ class Binder - - def initialize(events, conf = Configuration.new) - @events = events -+ @conf = conf - @listeners = [] - @inherited_fds = {} - @activated_sockets = {} -@@ -234,7 +235,17 @@ def parse(binds, logger, log_msg = 'Listening') - # Load localhost authority if not loaded. - ctx = localhost_authority && localhost_authority_context if params.empty? - -- ctx ||= MiniSSL::ContextBuilder.new(params, @events).context -+ ctx ||= -+ begin -+ # Extract cert_pem and key_pem from options[:store] if present -+ ['cert', 'key'].each do |v| -+ if params[v] && params[v].start_with?('store:') -+ index = Integer(params.delete(v).split('store:').last) -+ params["#{v}_pem"] = @conf.options[:store][index] -+ end -+ end -+ MiniSSL::ContextBuilder.new(params, @events).context -+ end - - if fd = @inherited_fds.delete(str) - logger.log "* Inherited #{str}" -diff --git a/lib/puma/dsl.rb b/lib/puma/dsl.rb -index c3e933751..65b3bbed9 100644 ---- a/lib/puma/dsl.rb -+++ b/lib/puma/dsl.rb -@@ -447,6 +447,14 @@ def threads(min, max) - # verify_mode: verify_mode, # default 'none' - # verification_flags: flags, # optional, not supported by JRuby - # } -+ # -+ # Alternatively, you can provide the cert_pem and key_pem: -+ # @example -+ # ssl_bind '127.0.0.1', '9292', { -+ # cert_pem: File.read(path_to_cert), -+ # key_pem: File.read(path_to_key), -+ # } -+ # - # @example For JRuby, two keys are required: keystore & keystore_pass. - # ssl_bind '127.0.0.1', '9292', { - # keystore: path_to_keystore, -@@ -455,6 +463,7 @@ def threads(min, max) - # verify_mode: verify_mode # default 'none' - # } - def ssl_bind(host, port, opts) -+ add_pem_values_to_options_store(opts) - bind self.class.ssl_bind_str(host, port, opts) - end - -@@ -927,5 +936,25 @@ def io_selector_backend(backend) - def mutate_stdout_and_stderr_to_sync_on_write(enabled=true) - @options[:mutate_stdout_and_stderr_to_sync_on_write] = enabled - end -+ -+ private -+ -+ # To avoid adding cert_pem and key_pem as URI params, we store them on the -+ # options[:store] from where Puma binder knows how to find and extract them. -+ def add_pem_values_to_options_store(opts) -+ return if defined?(JRUBY_VERSION) -+ -+ @options[:store] ||= [] -+ -+ # Store cert_pem and key_pem to options[:store] if present -+ [:cert, :key].each do |v| -+ opt_key = :"#{v}_pem" -+ if opts[opt_key] -+ index = @options[:store].length -+ @options[:store] << opts[opt_key] -+ opts[v] = "store:#{index}" -+ end -+ end -+ end - end - end -diff --git a/lib/puma/minissl.rb b/lib/puma/minissl.rb -index 9f1bc8185..f9161af76 100644 ---- a/lib/puma/minissl.rb -+++ b/lib/puma/minissl.rb -@@ -208,6 +208,10 @@ class Context - def initialize - @no_tlsv1 = false - @no_tlsv1_1 = false -+ @key = nil -+ @cert = nil -+ @key_pem = nil -+ @cert_pem = nil - end - - if IS_JRUBY -@@ -230,6 +234,8 @@ def check - attr_reader :key - attr_reader :cert - attr_reader :ca -+ attr_reader :cert_pem -+ attr_reader :key_pem - attr_accessor :ssl_cipher_filter - attr_accessor :verification_flags - -@@ -248,9 +254,19 @@ def ca=(ca) - @ca = ca - end - -+ def cert_pem=(cert_pem) -+ raise ArgumentError, "'cert_pem' is not a String" unless cert_pem.is_a? String -+ @cert_pem = cert_pem -+ end -+ -+ def key_pem=(key_pem) -+ raise ArgumentError, "'key_pem' is not a String" unless key_pem.is_a? String -+ @key_pem = key_pem -+ end -+ - def check -- raise "Key not configured" unless @key -- raise "Cert not configured" unless @cert -+ raise "Key not configured" if @key.nil? && @key_pem.nil? -+ raise "Cert not configured" if @cert.nil? && @cert_pem.nil? - end - end - -diff --git a/lib/puma/minissl/context_builder.rb b/lib/puma/minissl/context_builder.rb -index a30a26dc3..8cf16bbd3 100644 ---- a/lib/puma/minissl/context_builder.rb -+++ b/lib/puma/minissl/context_builder.rb -@@ -23,17 +23,19 @@ def context - ctx.keystore_pass = params['keystore-pass'] - ctx.ssl_cipher_list = params['ssl_cipher_list'] if params['ssl_cipher_list'] - else -- unless params['key'] -- events.error "Please specify the SSL key via 'key='" -+ if params['key'].nil? && params['key_pem'].nil? -+ events.error "Please specify the SSL key via 'key=' or 'key_pem='" - end - -- ctx.key = params['key'] -+ ctx.key = params['key'] if params['key'] -+ ctx.key_pem = params['key_pem'] if params['key_pem'] - -- unless params['cert'] -- events.error "Please specify the SSL cert via 'cert='" -+ if params['cert'].nil? && params['cert_pem'].nil? -+ events.error "Please specify the SSL cert via 'cert=' or 'cert_pem='" - end - -- ctx.cert = params['cert'] -+ ctx.cert = params['cert'] if params['cert'] -+ ctx.cert_pem = params['cert_pem'] if params['cert_pem'] - - if ['peer', 'force_peer'].include?(params['verify_mode']) - unless params['ca'] -diff --git a/test/test_binder.rb b/test/test_binder.rb -index c4a027ab6..4dddbcce5 100644 ---- a/test/test_binder.rb -+++ b/test/test_binder.rb -@@ -262,7 +262,7 @@ def test_env_contains_protoenv - env_hash = @binder.envs[@binder.ios.first] - - @binder.proto_env.each do |k,v| -- assert_equal env_hash[k], v -+ assert env_hash[k] == v - end - end - -@@ -308,11 +308,11 @@ def test_redirects_for_restart_env - def test_close_listeners_closes_ios - @binder.parse ["tcp://127.0.0.1:#{UniquePort.call}"], @events - -- refute @binder.listeners.any? { |u, l| l.closed? } -+ refute @binder.listeners.any? { |_l, io| io.closed? } - - @binder.close_listeners - -- assert @binder.listeners.all? { |u, l| l.closed? } -+ assert @binder.listeners.all? { |_l, io| io.closed? } - end - - def test_close_listeners_closes_ios_unless_closed? -@@ -322,11 +322,11 @@ def test_close_listeners_closes_ios_unless_closed? - bomb.close - def bomb.close; raise "Boom!"; end # the bomb has been planted - -- assert @binder.listeners.any? { |u, l| l.closed? } -+ assert @binder.listeners.any? { |_l, io| io.closed? } - - @binder.close_listeners - -- assert @binder.listeners.all? { |u, l| l.closed? } -+ assert @binder.listeners.all? { |_l, io| io.closed? } - end - - def test_listeners_file_unlink_if_unix_listener -@@ -344,8 +344,8 @@ def test_import_from_env_listen_inherit - @binder.parse ["tcp://127.0.0.1:0"], @events - removals = @binder.create_inherited_fds(@binder.redirects_for_restart_env) - -- @binder.listeners.each do |url, io| -- assert_equal io.to_i, @binder.inherited_fds[url] -+ @binder.listeners.each do |l, io| -+ assert_equal io.to_i, @binder.inherited_fds[l] - end - assert_includes removals, "PUMA_INHERIT_0" - end -diff --git a/test/test_config.rb b/test/test_config.rb -index 9ba564653..758910ca1 100644 ---- a/test/test_config.rb -+++ b/test/test_config.rb -@@ -77,6 +77,28 @@ def test_ssl_bind - assert_equal [ssl_binding], conf.options[:binds] - end - -+ def test_ssl_bind_with_cert_and_key_pem -+ skip_if :jruby -+ skip_unless :ssl -+ -+ cert_path = File.expand_path "../examples/puma/client-certs", __dir__ -+ cert_pem = File.read("#{cert_path}/server.crt") -+ key_pem = File.read("#{cert_path}/server.key") -+ -+ conf = Puma::Configuration.new do |c| -+ c.ssl_bind "0.0.0.0", "9292", { -+ cert_pem: cert_pem, -+ key_pem: key_pem, -+ verify_mode: "the_verify_mode", -+ } -+ end -+ -+ conf.load -+ -+ ssl_binding = "ssl://0.0.0.0:9292?cert=store:0&key=store:1&verify_mode=the_verify_mode" -+ assert_equal [ssl_binding], conf.options[:binds] -+ end -+ - def test_ssl_bind_jruby - skip_unless :jruby - skip_unless :ssl -diff --git a/test/test_integration_ssl.rb b/test/test_integration_ssl.rb -index 8f746e5ab..9c3409a7b 100644 ---- a/test/test_integration_ssl.rb -+++ b/test/test_integration_ssl.rb -@@ -21,17 +21,47 @@ def teardown - super - end - -- def generate_config(opts = nil) -- @bind_port = UniquePort.call -- @control_tcp_port = UniquePort.call -+ def bind_port -+ @bind_port ||= UniquePort.call -+ end -+ -+ def control_tcp_port -+ @control_tcp_port ||= UniquePort.call -+ end -+ -+ def with_server(config) -+ config_file = Tempfile.new %w(config .rb) -+ config_file.write config -+ config_file.close -+ config_file.path -+ -+ # start server -+ cmd = "#{BASE} bin/puma -C #{config_file.path}" -+ @server = IO.popen cmd, 'r' -+ wait_for_server_to_boot -+ @pid = @server.pid - -+ http = Net::HTTP.new HOST, bind_port -+ http.use_ssl = true -+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE -+ -+ yield http -+ -+ # stop server -+ sock = TCPSocket.new HOST, control_tcp_port -+ @ios_to_close << sock -+ sock.syswrite "GET /stop?token=#{TOKEN} HTTP/1.1\r\n\r\n" -+ sock.read -+ assert_match 'Goodbye!', @server.read -+ end -+ -+ def test_ssl_run - config = < e -+ # Errno::ECONNRESET TruffleRuby -+ client_error = e -+ # closes socket if open, may not close on error -+ http.send :do_finish -+ end -+ -+ assert_nil client_error -+ ensure -+ server.stop(true) if server -+ end -+end if ::Puma::HAS_SSL && !Puma::IS_JRUBY diff --git a/puma-5.5.2.gem b/puma-5.5.2.gem deleted file mode 100644 index e78209f0547ea189625ccf271402ea249b3cd929..0000000000000000000000000000000000000000 Binary files a/puma-5.5.2.gem and /dev/null differ diff --git a/puma-5.6.5.gem b/puma-5.6.5.gem new file mode 100644 index 0000000000000000000000000000000000000000..b1a94488ef6d23dc2427be916e16e7112c7c5ed9 Binary files /dev/null and b/puma-5.6.5.gem differ diff --git a/rubygem-puma-3.6.0-fedora-crypto-policy-cipher-list.patch b/rubygem-puma-3.6.0-fedora-crypto-policy-cipher-list.patch index 1e9954f50e9bdd92ecafcc274350e6a5e774672a..b2c45778df60e48f766bc529ff3f280ec6736cf7 100644 --- a/rubygem-puma-3.6.0-fedora-crypto-policy-cipher-list.patch +++ b/rubygem-puma-3.6.0-fedora-crypto-policy-cipher-list.patch @@ -2,7 +2,7 @@ diff --git a/ext/puma_http11/mini_ssl.c b/ext/puma_http11/mini_ssl.c index 7e0fd5e..88c4652 100644 --- a/ext/puma_http11/mini_ssl.c +++ b/ext/puma_http11/mini_ssl.c -@@ -286,7 +286,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { +@@ -336,7 +336,7 @@ sslctx_initialize(VALUE self, VALUE mini_ssl_ctx) { SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(ssl_cipher_filter)); } else { @@ -10,7 +10,7 @@ index 7e0fd5e..88c4652 100644 + SSL_CTX_set_cipher_list(ctx, "PROFILE=SYSTEM"); } - dh = get_dh2048(); + #if OPENSSL_VERSION_NUMBER < 0x10002000L -- 2.30.0 diff --git a/rubygem-puma.spec b/rubygem-puma.spec index 6f5976df77985936386027652becbafea3efa4dd..64a2a839e70a0b5f2e2d6b814d91eab9203824c8 100644 --- a/rubygem-puma.spec +++ b/rubygem-puma.spec @@ -1,8 +1,8 @@ %global gem_name puma %bcond_with ragel Name: rubygem-%{gem_name} -Version: 5.5.2 -Release: 4 +Version: 5.6.5 +Release: 1 Summary: A simple, fast, threaded, and highly concurrent HTTP 1.1 server License: BSD-3-Clause URL: http://puma.io @@ -11,10 +11,8 @@ Source1: https://github.com/puma/%{gem_name}/archive/refs/tags/v%{ve # Set the default cipher list "PROFILE=SYSTEM". # https://fedoraproject.org/wiki/Packaging:CryptoPolicies Patch0: rubygem-puma-3.6.0-fedora-crypto-policy-cipher-list.patch -Patch1: Support-for-cert_pem-and-key_pem-with-ssl_bind-DSL.patch -# https://github.com/puma/puma/commit/b70f451fe8abc0cff192c065d549778452e155bb -Patch2: CVE-2022-23634.patch -Patch3: CVE-2024-21647.patch +Patch1: CVE-2023-40175.patch +Patch2: CVE-2024-21647.patch BuildRequires: openssl-devel ruby(release) rubygems-devel ruby-devel rubygem(rack) BuildRequires: rubygem(minitest) rubygem(sd_notify) @@ -39,7 +37,6 @@ Documentation for %{name}. %patch0 -p1 %patch1 -p1 %patch2 -p1 -%patch3 -p1 rm -rf test/test_thread_pool.rb %if %{with ragel} @@ -86,6 +83,13 @@ sed -i -e '/^\s*def test_prune_bundler_with_multiple_workers$/a\ skip' test/test_integration_pumactl.rb mv test/test_puma_localhost_authority.rb{,.disable} + +sed -i '/def test_ssl_self_signed_configuration_from_DSL/a\ + skip' test/test_config.rb +sed -i '/def test_ssl_run_with_localhost_authority/a\ + skip' test/test_integration_ssl.rb +sed -i "s/--tlsv1.2 --tls-max 1.2/--tlsv1.3 --tls-max 1.3/" test/test_integration_ssl.rb + mv test/test_integration_single.rb{,.disable} mv test/test_integration_cluster.rb{,.disable} @@ -99,11 +103,19 @@ sed -i '/^ def test_plugin$/a\ skip' test/test_plugin.rb sed -i '/^ def test_verify_fail_if_client_unknown_ca$/a\ skip' test/test_puma_server_ssl.rb +sed -i '/^ def test_rack_url_scheme_dflt$/a\ + skip' test/test_puma_server.rb +sed -i '/^ def test_drain_on_shutdown$/a\ + skip' test/test_puma_server.rb +sed -i '/^ def test_very_large_return$/a\ + skip' test/test_puma_server.rb +env -u NOTIFY_SOCKET \ +TEST_CASE_TIMEOUT=300 \ RUBYOPT="-Ilib:$(dirs +1 -l)%{gem_extdir_mri}" \ CI=1 \ LC_ALL=C.UTF-8 \ -ruby -e 'Dir.glob "./test/**/test_*.rb", &method(:require)' +ruby -e 'Dir.glob "./test/**/test_*.rb", &method(:require)' - -v %files %dir %{gem_instdir} @@ -124,6 +136,10 @@ ruby -e 'Dir.glob "./test/**/test_*.rb", &method(:require)' %{gem_instdir}/tools %changelog +* Thu Apr 11 2024 wangkai <13474090681@163.com> - 5.6.5-1 +- Update to 5.6.5 +- Fix CVE-2022-24790,CVE-2023-40175 + * Fri Jan 12 2024 wangkai <13474090681@163.com> - 5.5.2-4 - Fix CVE-2024-21647 diff --git a/v5.5.2.tar.gz b/v5.5.2.tar.gz deleted file mode 100644 index c56b95b5cac993b75fb62780531bf03a07676b2b..0000000000000000000000000000000000000000 Binary files a/v5.5.2.tar.gz and /dev/null differ diff --git a/v5.6.5.tar.gz b/v5.6.5.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..7f2dce00ab2143b0a6738f1f7e4e2740252823a8 Binary files /dev/null and b/v5.6.5.tar.gz differ