diff --git a/CVE-2021-41136-1.patch b/CVE-2021-41136-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..90ff0819c281a45e15c3abfe3290b9925419f47c --- /dev/null +++ b/CVE-2021-41136-1.patch @@ -0,0 +1,52 @@ +From ab4e1babf314a9401dbb18a56399554da1121252 Mon Sep 17 00:00:00 2001 +From: Nate Berkopec +Date: Tue, 6 Aug 2019 16:55:40 -0700 +Subject: [PATCH 1/1] Failing/skipped test for #1890 + +--- + config.ru | 1 + + test/test_http11.rb | 12 ++++++++++++ + 2 files changed, 13 insertions(+) + create mode 100644 config.ru + +diff --git a/config.ru b/config.ru +new file mode 100644 +index 00000000..65ce25ff +--- /dev/null ++++ b/config.ru +@@ -0,0 +1 @@ ++run(proc{|env| [200, {}, [env['HTTP_FOO'].inspect, "\n"]]}) +\ No newline at end of file +diff --git a/test/test_http11.rb b/test/test_http11.rb +index 2a300470..3725a639 100644 +--- a/test/test_http11.rb ++++ b/test/test_http11.rb +@@ -2,6 +2,7 @@ + # Copyright (c) 2005 Zed A. Shaw + + require_relative "helper" ++require "digest" + + require "puma/puma_http11" + +@@ -181,6 +182,17 @@ class Http11ParserTest < Minitest::Test + parser.reset + end + end ++ end ++ ++ # https://github.com/puma/puma/issues/1890 ++ def test_trims_whitespace_from_headers ++ skip("Known failure, see issue 1890 on GitHub") ++ parser = Puma::HttpParser.new ++ req = {} ++ http = "GET / HTTP/1.1\r\nX-Strip-Me: Strip This \r\n\r\n" + ++ nread = parser.execute(req, http, 0) ++ ++ assert_equal "Strip This", req["HTTP_X_STRIP_ME"] + end + end +-- +2.23.0 + diff --git a/CVE-2021-41136-2.patch b/CVE-2021-41136-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..4612ee31255054e9cd8f767bed09871ced498777 --- /dev/null +++ b/CVE-2021-41136-2.patch @@ -0,0 +1,67 @@ +From 22b135a636bb3a80875e4f46b48610fa32fcd9d6 Mon Sep 17 00:00:00 2001 +From: Nate Berkopec +Date: Mon, 7 Oct 2019 15:23:18 +0200 +Subject: [PATCH] Strip header whitespace. Fix #1890. Code by @matthewd (#2010) + +--- + ext/puma_http11/org/jruby/puma/Http11.java | 8 ++++++-- + ext/puma_http11/puma_http11.c | 2 ++ + test/test_http11.rb | 2 -- + 3 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/ext/puma_http11/org/jruby/puma/Http11.java b/ext/puma_http11/org/jruby/puma/Http11.java +index 59dde37..7e38c2b 100644 +--- a/ext/puma_http11/org/jruby/puma/Http11.java ++++ b/ext/puma_http11/org/jruby/puma/Http11.java +@@ -87,7 +87,9 @@ public class Http11 extends RubyObject { + validateMaxLength(flen, MAX_FIELD_NAME_LENGTH, MAX_FIELD_NAME_LENGTH_ERR); + validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR); + +- ByteList b = new ByteList(Http11.this.hp.parser.buffer,field,flen); ++ ByteList buffer = Http11.this.hp.parser.buffer; ++ ++ ByteList b = new ByteList(buffer,field,flen); + for(int i = 0,j = b.length();i 0 && Character.isWhitespace(buffer.get(value + vlen - 1))) vlen--; ++ ++ b = new ByteList(buffer, value, vlen); + v = req.op_aref(req.getRuntime().getCurrentContext(), f); + if (v.isNil()) { + req.op_aset(req.getRuntime().getCurrentContext(), f, RubyString.newString(runtime, b)); +diff --git a/ext/puma_http11/puma_http11.c b/ext/puma_http11/puma_http11.c +index 79e706d..7ac1b47 100644 +--- a/ext/puma_http11/puma_http11.c ++++ b/ext/puma_http11/puma_http11.c +@@ -200,6 +200,8 @@ void http_field(puma_parser* hp, const char *field, size_t flen, + f = rb_str_new(hp->buf, new_size); + } + ++ while (vlen > 0 && isspace(value[vlen - 1])) vlen--; ++ + /* check for duplicate header */ + v = rb_hash_aref(hp->request, f); + +diff --git a/test/test_http11.rb b/test/test_http11.rb +index 3725a63..c20c476 100644 +--- a/test/test_http11.rb ++++ b/test/test_http11.rb +@@ -184,9 +184,7 @@ class Http11ParserTest < Minitest::Test + end + end + +- # https://github.com/puma/puma/issues/1890 + def test_trims_whitespace_from_headers +- skip("Known failure, see issue 1890 on GitHub") + parser = Puma::HttpParser.new + req = {} + http = "GET / HTTP/1.1\r\nX-Strip-Me: Strip This \r\n\r\n" +-- +2.23.0 + diff --git a/CVE-2021-41136-3.patch b/CVE-2021-41136-3.patch new file mode 100644 index 0000000000000000000000000000000000000000..f3a1aaac56dc0fdc668df60dc069a09a1797bac6 --- /dev/null +++ b/CVE-2021-41136-3.patch @@ -0,0 +1,630 @@ +From c81b0dd3d222cf069c85d28479105b6269a679c4 Mon Sep 17 00:00:00 2001 +From: Charles Oliver Nutter +Date: Sat, 5 Oct 2019 12:33:04 -0500 +Subject: [PATCH 1/1] Reduce accesses of runtime, parser by passing through. + +--- + ext/puma_http11/http11_parser.java.rl | 26 +-- + ext/puma_http11/org/jruby/puma/Http11.java | 63 +++--- + .../org/jruby/puma/Http11Parser.java | 191 +++++++++--------- + 3 files changed, 141 insertions(+), 139 deletions(-) + +diff --git a/ext/puma_http11/http11_parser.java.rl b/ext/puma_http11/http11_parser.java.rl +index 3c9a403..d0ab2fc 100644 +--- a/ext/puma_http11/http11_parser.java.rl ++++ b/ext/puma_http11/http11_parser.java.rl +@@ -1,5 +1,7 @@ + package org.jruby.puma; + ++import org.jruby.Ruby; ++import org.jruby.RubyHash; + import org.jruby.util.ByteList; + + public class Http11Parser { +@@ -21,42 +23,42 @@ public class Http11Parser { + action start_value { parser.mark = fpc; } + action write_value { + if(parser.http_field != null) { +- parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark); ++ parser.http_field.call(runtime, parser.data, parser.buffer, parser.field_start, parser.field_len, parser.mark, fpc-parser.mark); + } + } + action request_method { + if(parser.request_method != null) +- parser.request_method.call(parser.data, parser.mark, fpc-parser.mark); ++ parser.request_method.call(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark); + } + action request_uri { + if(parser.request_uri != null) +- parser.request_uri.call(parser.data, parser.mark, fpc-parser.mark); ++ parser.request_uri.call(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark); + } + action fragment { + if(parser.fragment != null) +- parser.fragment.call(parser.data, parser.mark, fpc-parser.mark); ++ parser.fragment.call(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark); + } + + action start_query {parser.query_start = fpc; } + action query_string { + if(parser.query_string != null) +- parser.query_string.call(parser.data, parser.query_start, fpc-parser.query_start); ++ parser.query_string.call(runtime, parser.data, parser.buffer, parser.query_start, fpc-parser.query_start); + } + + action http_version { + if(parser.http_version != null) +- parser.http_version.call(parser.data, parser.mark, fpc-parser.mark); ++ parser.http_version.call(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark); + } + + action request_path { + if(parser.request_path != null) +- parser.request_path.call(parser.data, parser.mark, fpc-parser.mark); ++ parser.request_path.call(runtime, parser.data, parser.buffer, parser.mark, fpc-parser.mark); + } + + action done { + parser.body_start = fpc + 1; + if(parser.header_done != null) +- parser.header_done.call(parser.data, fpc + 1, pe - fpc - 1); ++ parser.header_done.call(runtime, parser.data, parser.buffer, fpc + 1, pe - fpc - 1); + fbreak; + } + +@@ -68,11 +70,11 @@ public class Http11Parser { + %% write data; + + public static interface ElementCB { +- public void call(Object data, int at, int length); ++ public void call(Ruby runtime, RubyHash data, ByteList buffer, int at, int length); + } + + public static interface FieldCB { +- public void call(Object data, int field, int flen, int value, int vlen); ++ public void call(Ruby runtime, RubyHash data, ByteList buffer, int field, int flen, int value, int vlen); + } + + public static class HttpParser { +@@ -85,7 +87,7 @@ public class Http11Parser { + int field_len; + int query_start; + +- Object data; ++ RubyHash data; + ByteList buffer; + + public FieldCB http_field; +@@ -113,7 +115,7 @@ public class Http11Parser { + + public final HttpParser parser = new HttpParser(); + +- public int execute(ByteList buffer, int off) { ++ public int execute(Ruby runtime, ByteList buffer, int off) { + int p, pe; + int cs = parser.cs; + int len = buffer.length(); +diff --git a/ext/puma_http11/org/jruby/puma/Http11.java b/ext/puma_http11/org/jruby/puma/Http11.java +index 7e38c2b..ef6329e 100644 +--- a/ext/puma_http11/org/jruby/puma/Http11.java ++++ b/ext/puma_http11/org/jruby/puma/Http11.java +@@ -20,6 +20,7 @@ import org.jruby.util.ByteList; + + /** + * @author Ola Bini ++ * @author Charles Oliver Nutter + */ + public class Http11 extends RubyObject { + public final static int MAX_FIELD_NAME_LENGTH = 256; +@@ -80,15 +81,12 @@ public class Http11 extends RubyObject { + } + + private Http11Parser.FieldCB http_field = new Http11Parser.FieldCB() { +- public void call(Object data, int field, int flen, int value, int vlen) { +- RubyHash req = (RubyHash)data; ++ public void call(Ruby runtime, RubyHash req, ByteList buffer, int field, int flen, int value, int vlen) { + RubyString f; + IRubyObject v; + validateMaxLength(flen, MAX_FIELD_NAME_LENGTH, MAX_FIELD_NAME_LENGTH_ERR); + validateMaxLength(vlen, MAX_FIELD_VALUE_LENGTH, MAX_FIELD_VALUE_LENGTH_ERR); + +- ByteList buffer = Http11.this.hp.parser.buffer; +- + ByteList b = new ByteList(buffer,field,flen); + for(int i = 0,j = b.length();i= d.length()) { + throw new RaiseException(runtime, eHttpParserError, "Requested start is after data buffer end.", true); + } else { +- this.hp.parser.data = req_hash; +- this.hp.execute(d,from); +- validateMaxLength(this.hp.parser.nread,MAX_HEADER_LENGTH, MAX_HEADER_LENGTH_ERR); +- if(this.hp.has_error()) { ++ Http11Parser hp = this.hp; ++ Http11Parser.HttpParser parser = hp.parser; ++ ++ parser.data = (RubyHash) req_hash; ++ ++ hp.execute(runtime, d,from); ++ ++ validateMaxLength(parser.nread,MAX_HEADER_LENGTH, MAX_HEADER_LENGTH_ERR); ++ ++ if(hp.has_error()) { + throw new RaiseException(runtime, eHttpParserError, "Invalid HTTP format, parsing fails.", true); + } else { +- return runtime.newFixnum(this.hp.parser.nread); ++ return runtime.newFixnum(parser.nread); + } + } + } +diff --git a/ext/puma_http11/org/jruby/puma/Http11Parser.java b/ext/puma_http11/org/jruby/puma/Http11Parser.java +index 626ee81..d208326 100644 +--- a/ext/puma_http11/org/jruby/puma/Http11Parser.java ++++ b/ext/puma_http11/org/jruby/puma/Http11Parser.java +@@ -2,6 +2,8 @@ + // line 1 "ext/puma_http11/http11_parser.java.rl" + package org.jruby.puma; + ++import org.jruby.Ruby; ++import org.jruby.RubyHash; + import org.jruby.util.ByteList; + + public class Http11Parser { +@@ -9,12 +11,12 @@ public class Http11Parser { + /** Machine **/ + + +-// line 65 "ext/puma_http11/http11_parser.java.rl" ++// line 67 "ext/puma_http11/http11_parser.java.rl" + + + /** Data **/ + +-// line 18 "ext/puma_http11/org/jruby/puma/Http11Parser.java" ++// line 20 "ext/puma_http11/org/jruby/puma/Http11Parser.java" + private static byte[] init__puma_parser_actions_0() + { + return new byte [] { +@@ -33,8 +35,8 @@ private static short[] init__puma_parser_key_offsets_0() + return new short [] { + 0, 0, 8, 17, 27, 29, 30, 31, 32, 33, 34, 36, + 39, 41, 44, 45, 61, 62, 78, 80, 81, 89, 97, 107, +- 115, 125, 134, 142, 150, 159, 168, 177, 186, 195, 204, 213, +- 222, 231, 240, 249, 258, 267, 276, 285, 294, 303, 312, 313 ++ 115, 124, 132, 140, 149, 158, 167, 176, 185, 194, 203, 212, ++ 221, 230, 239, 248, 257, 266, 275, 284, 293, 302, 303 + }; + } + +@@ -53,24 +55,23 @@ private static char[] init__puma_parser_trans_keys_0() + 48, 57, 65, 90, 94, 122, 13, 32, 13, 32, 60, 62, + 127, 0, 31, 34, 35, 32, 60, 62, 127, 0, 31, 34, + 35, 43, 58, 45, 46, 48, 57, 65, 90, 97, 122, 32, +- 34, 35, 60, 62, 127, 0, 31, 32, 34, 35, 59, 60, +- 62, 63, 127, 0, 31, 32, 34, 35, 60, 62, 63, 127, +- 0, 31, 32, 34, 35, 60, 62, 127, 0, 31, 32, 34, +- 35, 60, 62, 127, 0, 31, 32, 36, 95, 45, 46, 48, +- 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, +- 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, +- 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, +- 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, +- 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, +- 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, +- 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, +- 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, +- 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, +- 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, +- 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, +- 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, +- 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, +- 32, 0 ++ 34, 35, 60, 62, 127, 0, 31, 32, 34, 35, 60, 62, ++ 63, 127, 0, 31, 32, 34, 35, 60, 62, 127, 0, 31, ++ 32, 34, 35, 60, 62, 127, 0, 31, 32, 36, 95, 45, ++ 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, ++ 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, ++ 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, ++ 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, ++ 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, ++ 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, ++ 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, ++ 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, ++ 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, ++ 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, ++ 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, ++ 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, ++ 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, ++ 65, 90, 32, 0 + }; + } + +@@ -82,8 +83,8 @@ private static byte[] init__puma_parser_single_lengths_0() + return new byte [] { + 0, 2, 3, 4, 2, 1, 1, 1, 1, 1, 0, 1, + 0, 1, 1, 4, 1, 4, 2, 1, 4, 4, 2, 6, +- 8, 7, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, +- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0 ++ 7, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0 + }; + } + +@@ -95,8 +96,8 @@ private static byte[] init__puma_parser_range_lengths_0() + return new byte [] { + 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 6, 0, 6, 0, 0, 2, 2, 4, 1, +- 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, +- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0 ++ 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0 + }; + } + +@@ -108,8 +109,8 @@ private static short[] init__puma_parser_index_offsets_0() + return new short [] { + 0, 0, 6, 13, 21, 24, 26, 28, 30, 32, 34, 36, + 39, 41, 44, 46, 57, 59, 70, 73, 75, 82, 89, 96, +- 104, 114, 123, 131, 139, 146, 153, 160, 167, 174, 181, 188, +- 195, 202, 209, 216, 223, 230, 237, 244, 251, 258, 265, 267 ++ 104, 113, 121, 129, 136, 143, 150, 157, 164, 171, 178, 185, ++ 192, 199, 206, 213, 220, 227, 234, 241, 248, 255, 257 + }; + } + +@@ -127,21 +128,20 @@ private static byte[] init__puma_parser_indicies_0() + 24, 23, 23, 23, 23, 23, 23, 23, 23, 1, 26, 27, + 25, 29, 28, 30, 1, 1, 1, 1, 1, 31, 32, 1, + 1, 1, 1, 1, 33, 34, 35, 34, 34, 34, 34, 1, +- 8, 1, 9, 1, 1, 1, 1, 35, 36, 1, 38, 39, +- 1, 1, 40, 1, 1, 37, 8, 1, 9, 1, 1, 42, +- 1, 1, 41, 43, 1, 45, 1, 1, 1, 1, 44, 46, +- 1, 48, 1, 1, 1, 1, 47, 2, 49, 49, 49, 49, +- 49, 1, 2, 50, 50, 50, 50, 50, 1, 2, 51, 51, +- 51, 51, 51, 1, 2, 52, 52, 52, 52, 52, 1, 2, +- 53, 53, 53, 53, 53, 1, 2, 54, 54, 54, 54, 54, +- 1, 2, 55, 55, 55, 55, 55, 1, 2, 56, 56, 56, +- 56, 56, 1, 2, 57, 57, 57, 57, 57, 1, 2, 58, +- 58, 58, 58, 58, 1, 2, 59, 59, 59, 59, 59, 1, +- 2, 60, 60, 60, 60, 60, 1, 2, 61, 61, 61, 61, +- 61, 1, 2, 62, 62, 62, 62, 62, 1, 2, 63, 63, +- 63, 63, 63, 1, 2, 64, 64, 64, 64, 64, 1, 2, +- 65, 65, 65, 65, 65, 1, 2, 66, 66, 66, 66, 66, +- 1, 2, 1, 1, 0 ++ 8, 1, 9, 1, 1, 1, 1, 35, 36, 1, 38, 1, ++ 1, 39, 1, 1, 37, 40, 1, 42, 1, 1, 1, 1, ++ 41, 43, 1, 45, 1, 1, 1, 1, 44, 2, 46, 46, ++ 46, 46, 46, 1, 2, 47, 47, 47, 47, 47, 1, 2, ++ 48, 48, 48, 48, 48, 1, 2, 49, 49, 49, 49, 49, ++ 1, 2, 50, 50, 50, 50, 50, 1, 2, 51, 51, 51, ++ 51, 51, 1, 2, 52, 52, 52, 52, 52, 1, 2, 53, ++ 53, 53, 53, 53, 1, 2, 54, 54, 54, 54, 54, 1, ++ 2, 55, 55, 55, 55, 55, 1, 2, 56, 56, 56, 56, ++ 56, 1, 2, 57, 57, 57, 57, 57, 1, 2, 58, 58, ++ 58, 58, 58, 1, 2, 59, 59, 59, 59, 59, 1, 2, ++ 60, 60, 60, 60, 60, 1, 2, 61, 61, 61, 61, 61, ++ 1, 2, 62, 62, 62, 62, 62, 1, 2, 63, 63, 63, ++ 63, 63, 1, 2, 1, 1, 0 + }; + } + +@@ -151,12 +151,12 @@ private static final byte _puma_parser_indicies[] = init__puma_parser_indicies_0 + private static byte[] init__puma_parser_trans_targs_0() + { + return new byte [] { +- 2, 0, 3, 28, 4, 22, 24, 23, 5, 20, 6, 7, +- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 47, 17, ++ 2, 0, 3, 27, 4, 22, 24, 23, 5, 20, 6, 7, ++ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 46, 17, + 18, 19, 14, 18, 19, 14, 5, 21, 5, 21, 22, 23, +- 5, 24, 20, 25, 26, 25, 26, 5, 27, 20, 5, 27, +- 20, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, +- 40, 41, 42, 43, 44, 45, 46 ++ 5, 24, 20, 25, 5, 26, 20, 5, 26, 20, 28, 29, ++ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, ++ 42, 43, 44, 45 + }; + } + +@@ -169,9 +169,9 @@ private static byte[] init__puma_parser_trans_actions_0() + 1, 0, 11, 0, 1, 1, 1, 1, 13, 13, 1, 0, + 0, 0, 0, 0, 0, 0, 19, 0, 0, 28, 23, 3, + 5, 7, 31, 7, 0, 9, 25, 1, 15, 0, 0, 0, +- 37, 0, 37, 21, 21, 0, 0, 40, 17, 40, 34, 0, +- 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +- 0, 0, 0, 0, 0, 0, 0 ++ 37, 0, 37, 21, 40, 17, 40, 34, 0, 34, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0 + }; + } + +@@ -179,17 +179,20 @@ private static final byte _puma_parser_trans_actions[] = init__puma_parser_trans + + + static final int puma_parser_start = 1; +-static final int puma_parser_first_final = 47; ++static final int puma_parser_first_final = 46; + static final int puma_parser_error = 0; + +-// line 69 "ext/puma_http11/http11_parser.java.rl" ++static final int puma_parser_en_main = 1; ++ ++ ++// line 71 "ext/puma_http11/http11_parser.java.rl" + + public static interface ElementCB { +- public void call(Object data, int at, int length); ++ public void call(Ruby runtime, RubyHash data, ByteList buffer, int at, int length); + } + + public static interface FieldCB { +- public void call(Object data, int field, int flen, int value, int vlen); ++ public void call(Ruby runtime, RubyHash data, ByteList buffer, int field, int flen, int value, int vlen); + } + + public static class HttpParser { +@@ -202,7 +205,7 @@ static final int puma_parser_error = 0; + int field_len; + int query_start; + +- Object data; ++ RubyHash data; + ByteList buffer; + + public FieldCB http_field; +@@ -217,13 +220,13 @@ static final int puma_parser_error = 0; + public void init() { + cs = 0; + +- ++ + // line 225 "ext/puma_http11/org/jruby/puma/Http11Parser.java" + { + cs = puma_parser_start; + } + +-// line 104 "ext/puma_http11/http11_parser.java.rl" ++// line 106 "ext/puma_http11/http11_parser.java.rl" + + body_start = 0; + content_len = 0; +@@ -236,7 +239,7 @@ static final int puma_parser_error = 0; + + public final HttpParser parser = new HttpParser(); + +- public int execute(ByteList buffer, int off) { ++ public int execute(Ruby runtime, ByteList buffer, int off) { + int p, pe; + int cs = parser.cs; + int len = buffer.length(); +@@ -249,7 +252,7 @@ static final int puma_parser_error = 0; + byte[] data = buffer.bytes(); + parser.buffer = buffer; + +- ++ + // line 257 "ext/puma_http11/org/jruby/puma/Http11Parser.java" + { + int _klen; +@@ -331,87 +334,87 @@ case 1: + switch ( _puma_parser_actions[_acts++] ) + { + case 0: +-// line 13 "ext/puma_http11/http11_parser.java.rl" ++// line 15 "ext/puma_http11/http11_parser.java.rl" + {parser.mark = p; } + break; + case 1: +-// line 15 "ext/puma_http11/http11_parser.java.rl" ++// line 17 "ext/puma_http11/http11_parser.java.rl" + { parser.field_start = p; } + break; + case 2: +-// line 16 "ext/puma_http11/http11_parser.java.rl" ++// line 18 "ext/puma_http11/http11_parser.java.rl" + { /* FIXME stub */ } + break; + case 3: +-// line 17 "ext/puma_http11/http11_parser.java.rl" +- { ++// line 19 "ext/puma_http11/http11_parser.java.rl" ++ { + parser.field_len = p-parser.field_start; + } + break; + case 4: +-// line 21 "ext/puma_http11/http11_parser.java.rl" ++// line 23 "ext/puma_http11/http11_parser.java.rl" + { parser.mark = p; } + break; + case 5: +-// line 22 "ext/puma_http11/http11_parser.java.rl" +- { ++// line 24 "ext/puma_http11/http11_parser.java.rl" ++ { + if(parser.http_field != null) { +- parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, p-parser.mark); ++ parser.http_field.call(runtime, parser.data, parser.buffer, parser.field_start, parser.field_len, parser.mark, p-parser.mark); + } + } + break; + case 6: +-// line 27 "ext/puma_http11/http11_parser.java.rl" +- { +- if(parser.request_method != null) +- parser.request_method.call(parser.data, parser.mark, p-parser.mark); ++// line 29 "ext/puma_http11/http11_parser.java.rl" ++ { ++ if(parser.request_method != null) ++ parser.request_method.call(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark); + } + break; + case 7: +-// line 31 "ext/puma_http11/http11_parser.java.rl" +- { ++// line 33 "ext/puma_http11/http11_parser.java.rl" ++ { + if(parser.request_uri != null) +- parser.request_uri.call(parser.data, parser.mark, p-parser.mark); ++ parser.request_uri.call(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark); + } + break; + case 8: +-// line 35 "ext/puma_http11/http11_parser.java.rl" +- { ++// line 37 "ext/puma_http11/http11_parser.java.rl" ++ { + if(parser.fragment != null) +- parser.fragment.call(parser.data, parser.mark, p-parser.mark); ++ parser.fragment.call(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark); + } + break; + case 9: +-// line 40 "ext/puma_http11/http11_parser.java.rl" ++// line 42 "ext/puma_http11/http11_parser.java.rl" + {parser.query_start = p; } + break; + case 10: +-// line 41 "ext/puma_http11/http11_parser.java.rl" +- { ++// line 43 "ext/puma_http11/http11_parser.java.rl" ++ { + if(parser.query_string != null) +- parser.query_string.call(parser.data, parser.query_start, p-parser.query_start); ++ parser.query_string.call(runtime, parser.data, parser.buffer, parser.query_start, p-parser.query_start); + } + break; + case 11: +-// line 46 "ext/puma_http11/http11_parser.java.rl" +- { ++// line 48 "ext/puma_http11/http11_parser.java.rl" ++ { + if(parser.http_version != null) +- parser.http_version.call(parser.data, parser.mark, p-parser.mark); ++ parser.http_version.call(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark); + } + break; + case 12: +-// line 51 "ext/puma_http11/http11_parser.java.rl" ++// line 53 "ext/puma_http11/http11_parser.java.rl" + { + if(parser.request_path != null) +- parser.request_path.call(parser.data, parser.mark, p-parser.mark); ++ parser.request_path.call(runtime, parser.data, parser.buffer, parser.mark, p-parser.mark); + } + break; + case 13: +-// line 56 "ext/puma_http11/http11_parser.java.rl" +- { +- parser.body_start = p + 1; ++// line 58 "ext/puma_http11/http11_parser.java.rl" ++ { ++ parser.body_start = p + 1; + if(parser.header_done != null) +- parser.header_done.call(parser.data, p + 1, pe - p - 1); ++ parser.header_done.call(runtime, parser.data, parser.buffer, p + 1, pe - p - 1); + { p += 1; _goto_targ = 5; if (true) continue _goto;} + } + break; +@@ -435,11 +438,11 @@ case 5: + break; } + } + +-// line 130 "ext/puma_http11/http11_parser.java.rl" ++// line 132 "ext/puma_http11/http11_parser.java.rl" + + parser.cs = cs; + parser.nread += (p - off); +- ++ + assert p <= pe : "buffer overflow after parsing execute"; + assert parser.nread <= len : "nread longer than length"; + assert parser.body_start <= len : "body starts after buffer end"; +-- +2.23.0 + diff --git a/CVE-2021-41136-4.patch b/CVE-2021-41136-4.patch new file mode 100644 index 0000000000000000000000000000000000000000..0b7815890c218ed0694d69edd3b260f3d5829ff7 --- /dev/null +++ b/CVE-2021-41136-4.patch @@ -0,0 +1,303 @@ +From acdc3ae571dfae0e045cf09a295280127db65c7f Mon Sep 17 00:00:00 2001 +From: Nate Berkopec +Date: Tue, 12 Oct 2021 08:38:40 -0600 +Subject: [PATCH] Merge pull request from GHSA-48w2-rm65-62xx + +--- + ext/puma_http11/http11_parser.c | 31 +++++---- + ext/puma_http11/http11_parser_common.rl | 2 +- + .../org/jruby/puma/Http11Parser.java | 68 +++++++++---------- + lib/puma/const.rb | 2 +- + test/test_http11.rb | 30 ++++++++ + 5 files changed, 85 insertions(+), 48 deletions(-) + +diff --git a/ext/puma_http11/http11_parser.c b/ext/puma_http11/http11_parser.c +index e8844a3..52660f0 100644 +--- a/ext/puma_http11/http11_parser.c ++++ b/ext/puma_http11/http11_parser.c +@@ -428,10 +428,13 @@ st18: + case 18: + #line 428 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { ++ case 9: goto tr25; + case 13: goto tr26; + case 32: goto tr27; + } +- goto tr25; ++ if ( 33 <= (*p) && (*p) <= 126 ) ++ goto tr25; ++ goto st0; + tr25: + #line 44 "ext/puma_http11/http11_parser.rl" + { MARK(mark, p); } +@@ -440,10 +443,14 @@ st19: + if ( ++p == pe ) + goto _test_eof19; + case 19: +-#line 442 "ext/puma_http11/http11_parser.c" +- if ( (*p) == 13 ) +- goto tr29; +- goto st19; ++#line 445 "ext/puma_http11/http11_parser.c" ++ switch( (*p) ) { ++ case 9: goto st19; ++ case 13: goto tr29; ++ } ++ if ( 32 <= (*p) && (*p) <= 126 ) ++ goto st19; ++ goto st0; + tr9: + #line 51 "ext/puma_http11/http11_parser.rl" + { +@@ -486,7 +493,7 @@ st20: + if ( ++p == pe ) + goto _test_eof20; + case 20: +-#line 488 "ext/puma_http11/http11_parser.c" ++#line 495 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr31; + case 60: goto st0; +@@ -507,7 +514,7 @@ st21: + if ( ++p == pe ) + goto _test_eof21; + case 21: +-#line 509 "ext/puma_http11/http11_parser.c" ++#line 516 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr33; + case 60: goto st0; +@@ -528,7 +535,7 @@ st22: + if ( ++p == pe ) + goto _test_eof22; + case 22: +-#line 530 "ext/puma_http11/http11_parser.c" ++#line 537 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 43: goto st22; + case 58: goto st23; +@@ -553,7 +560,7 @@ st23: + if ( ++p == pe ) + goto _test_eof23; + case 23: +-#line 555 "ext/puma_http11/http11_parser.c" ++#line 562 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr8; + case 34: goto st0; +@@ -573,7 +580,7 @@ st24: + if ( ++p == pe ) + goto _test_eof24; + case 24: +-#line 575 "ext/puma_http11/http11_parser.c" ++#line 582 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr37; + case 34: goto st0; +@@ -597,7 +604,7 @@ st25: + if ( ++p == pe ) + goto _test_eof25; + case 25: +-#line 599 "ext/puma_http11/http11_parser.c" ++#line 605 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr8; + case 34: goto st0; +@@ -620,7 +627,7 @@ st26: + if ( ++p == pe ) + goto _test_eof26; + case 26: +-#line 622 "ext/puma_http11/http11_parser.c" ++#line 625 "ext/puma_http11/http11_parser.c" + switch( (*p) ) { + case 32: goto tr44; + case 34: goto st0; +diff --git a/ext/puma_http11/http11_parser_common.rl b/ext/puma_http11/http11_parser_common.rl +index a4cf89d..567a786 100644 +--- a/ext/puma_http11/http11_parser_common.rl ++++ b/ext/puma_http11/http11_parser_common.rl +@@ -43,7 +43,7 @@ + + field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field; + +- field_value = any* >start_value %write_value; ++ field_value = ( print | "\t" )* >start_value %write_value; + + message_header = field_name ":" " "* field_value :> CRLF; + +diff --git a/ext/puma_http11/org/jruby/puma/Http11Parser.java b/ext/puma_http11/org/jruby/puma/Http11Parser.java +index d208326..a766aa7 100644 +--- a/ext/puma_http11/org/jruby/puma/Http11Parser.java ++++ b/ext/puma_http11/org/jruby/puma/Http11Parser.java +@@ -34,9 +34,9 @@ private static short[] init__puma_parser_key_offsets_0() + { + return new short [] { + 0, 0, 8, 17, 27, 29, 30, 31, 32, 33, 34, 36, +- 39, 41, 44, 45, 61, 62, 78, 80, 81, 89, 97, 107, +- 115, 124, 132, 140, 149, 158, 167, 176, 185, 194, 203, 212, +- 221, 230, 239, 248, 257, 266, 275, 284, 293, 302, 303 ++ 39, 41, 44, 45, 61, 62, 78, 83, 87, 95, 103, 113, ++ 121, 130, 138, 146, 155, 164, 173, 182, 191, 200, 209, 218, ++ 227, 236, 245, 254, 263, 272, 281, 290, 299, 308, 309 + }; + } + +@@ -52,14 +52,13 @@ private static char[] init__puma_parser_trans_keys_0() + 46, 48, 57, 48, 57, 13, 48, 57, 10, 13, 33, 124, + 126, 35, 39, 42, 43, 45, 46, 48, 57, 65, 90, 94, + 122, 10, 33, 58, 124, 126, 35, 39, 42, 43, 45, 46, +- 48, 57, 65, 90, 94, 122, 13, 32, 13, 32, 60, 62, +- 127, 0, 31, 34, 35, 32, 60, 62, 127, 0, 31, 34, +- 35, 43, 58, 45, 46, 48, 57, 65, 90, 97, 122, 32, +- 34, 35, 60, 62, 127, 0, 31, 32, 34, 35, 60, 62, +- 63, 127, 0, 31, 32, 34, 35, 60, 62, 127, 0, 31, +- 32, 34, 35, 60, 62, 127, 0, 31, 32, 36, 95, 45, +- 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, +- 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, ++ 48, 57, 65, 90, 94, 122, 9, 13, 32, 33, 126, 9, ++ 13, 32, 126, 32, 60, 62, 127, 0, 31, 34, 35, 32, ++ 60, 62, 127, 0, 31, 34, 35, 43, 58, 45, 46, 48, ++ 57, 65, 90, 97, 122, 32, 34, 35, 60, 62, 127, 0, ++ 31, 32, 34, 35, 60, 62, 63, 127, 0, 31, 32, 34, ++ 35, 60, 62, 127, 0, 31, 32, 34, 35, 60, 62, 127, ++ 0, 31, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, + 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, + 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, + 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, +@@ -71,7 +70,8 @@ private static char[] init__puma_parser_trans_keys_0() + 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, + 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, + 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, +- 65, 90, 32, 0 ++ 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, ++ 36, 95, 45, 46, 48, 57, 65, 90, 32, 0 + }; + } + +@@ -82,7 +82,7 @@ private static byte[] init__puma_parser_single_lengths_0() + { + return new byte [] { + 0, 2, 3, 4, 2, 1, 1, 1, 1, 1, 0, 1, +- 0, 1, 1, 4, 1, 4, 2, 1, 4, 4, 2, 6, ++ 0, 1, 1, 4, 1, 4, 3, 2, 4, 4, 2, 6, + 7, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0 + }; +@@ -95,7 +95,7 @@ private static byte[] init__puma_parser_range_lengths_0() + { + return new byte [] { + 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 1, 1, +- 1, 1, 0, 6, 0, 6, 0, 0, 2, 2, 4, 1, ++ 1, 1, 0, 6, 0, 6, 1, 1, 2, 2, 4, 1, + 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0 + }; +@@ -108,9 +108,9 @@ private static short[] init__puma_parser_index_offsets_0() + { + return new short [] { + 0, 0, 6, 13, 21, 24, 26, 28, 30, 32, 34, 36, +- 39, 41, 44, 46, 57, 59, 70, 73, 75, 82, 89, 96, +- 104, 113, 121, 129, 136, 143, 150, 157, 164, 171, 178, 185, +- 192, 199, 206, 213, 220, 227, 234, 241, 248, 255, 257 ++ 39, 41, 44, 46, 57, 59, 70, 75, 79, 86, 93, 100, ++ 108, 117, 125, 133, 140, 147, 154, 161, 168, 175, 182, 189, ++ 196, 203, 210, 217, 224, 231, 238, 245, 252, 259, 261 + }; + } + +@@ -125,23 +125,23 @@ private static byte[] init__puma_parser_indicies_0() + 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, + 16, 15, 1, 17, 1, 18, 17, 1, 19, 1, 20, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 1, 22, 1, 23, +- 24, 23, 23, 23, 23, 23, 23, 23, 23, 1, 26, 27, +- 25, 29, 28, 30, 1, 1, 1, 1, 1, 31, 32, 1, +- 1, 1, 1, 1, 33, 34, 35, 34, 34, 34, 34, 1, +- 8, 1, 9, 1, 1, 1, 1, 35, 36, 1, 38, 1, +- 1, 39, 1, 1, 37, 40, 1, 42, 1, 1, 1, 1, +- 41, 43, 1, 45, 1, 1, 1, 1, 44, 2, 46, 46, +- 46, 46, 46, 1, 2, 47, 47, 47, 47, 47, 1, 2, +- 48, 48, 48, 48, 48, 1, 2, 49, 49, 49, 49, 49, +- 1, 2, 50, 50, 50, 50, 50, 1, 2, 51, 51, 51, +- 51, 51, 1, 2, 52, 52, 52, 52, 52, 1, 2, 53, +- 53, 53, 53, 53, 1, 2, 54, 54, 54, 54, 54, 1, +- 2, 55, 55, 55, 55, 55, 1, 2, 56, 56, 56, 56, +- 56, 1, 2, 57, 57, 57, 57, 57, 1, 2, 58, 58, +- 58, 58, 58, 1, 2, 59, 59, 59, 59, 59, 1, 2, +- 60, 60, 60, 60, 60, 1, 2, 61, 61, 61, 61, 61, +- 1, 2, 62, 62, 62, 62, 62, 1, 2, 63, 63, 63, +- 63, 63, 1, 2, 1, 1, 0 ++ 24, 23, 23, 23, 23, 23, 23, 23, 23, 1, 25, 26, ++ 27, 25, 1, 28, 29, 28, 1, 30, 1, 1, 1, 1, ++ 1, 31, 32, 1, 1, 1, 1, 1, 33, 34, 35, 34, ++ 34, 34, 34, 1, 8, 1, 9, 1, 1, 1, 1, 35, ++ 36, 1, 38, 1, 1, 39, 1, 1, 37, 40, 1, 42, ++ 1, 1, 1, 1, 41, 43, 1, 45, 1, 1, 1, 1, ++ 44, 2, 46, 46, 46, 46, 46, 1, 2, 47, 47, 47, ++ 47, 47, 1, 2, 48, 48, 48, 48, 48, 1, 2, 49, ++ 49, 49, 49, 49, 1, 2, 50, 50, 50, 50, 50, 1, ++ 2, 51, 51, 51, 51, 51, 1, 2, 52, 52, 52, 52, ++ 52, 1, 2, 53, 53, 53, 53, 53, 1, 2, 54, 54, ++ 54, 54, 54, 1, 2, 55, 55, 55, 55, 55, 1, 2, ++ 56, 56, 56, 56, 56, 1, 2, 57, 57, 57, 57, 57, ++ 1, 2, 58, 58, 58, 58, 58, 1, 2, 59, 59, 59, ++ 59, 59, 1, 2, 60, 60, 60, 60, 60, 1, 2, 61, ++ 61, 61, 61, 61, 1, 2, 62, 62, 62, 62, 62, 1, ++ 2, 63, 63, 63, 63, 63, 1, 2, 1, 1, 0 + }; + } + +diff --git a/lib/puma/const.rb b/lib/puma/const.rb +index 8b08ed0..1753edc 100644 +--- a/lib/puma/const.rb ++++ b/lib/puma/const.rb +@@ -100,7 +100,7 @@ module Puma + # too taxing on performance. + module Const + +- PUMA_VERSION = VERSION = "3.12.6".freeze ++ PUMA_VERSION = VERSION = "5.5.1".freeze + CODE_NAME = "Llamas in Pajamas".freeze + PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze + +diff --git a/test/test_http11.rb b/test/test_http11.rb +index c20c476..6a82b18 100644 +--- a/test/test_http11.rb ++++ b/test/test_http11.rb +@@ -193,4 +193,34 @@ class Http11ParserTest < Minitest::Test + + assert_equal "Strip This", req["HTTP_X_STRIP_ME"] + end ++ ++ def test_newline_smuggler ++ parser = Puma::HttpParser.new ++ req = {} ++ http = "GET / HTTP/1.1\r\nHost: localhost:8080\r\nDummy: x\nDummy2: y\r\n\r\n" ++ ++ parser.execute(req, http, 0) rescue nil # We test the raise elsewhere. ++ ++ assert parser.error?, "Parser SHOULD have error" ++ end ++ ++ def test_newline_smuggler_two ++ parser = Puma::HttpParser.new ++ req = {} ++ http = "GET / HTTP/1.1\r\nHost: localhost:8080\r\nDummy: x\r\nDummy: y\nDummy2: z\r\n\r\n" ++ ++ parser.execute(req, http, 0) rescue nil ++ ++ assert parser.error?, "Parser SHOULD have error" ++ end ++ ++ def test_htab_in_header_val ++ parser = Puma::HttpParser.new ++ req = {} ++ http = "GET / HTTP/1.1\r\nHost: localhost:8080\r\nDummy: Valid\tValue\r\n\r\n" ++ ++ parser.execute(req, http, 0) ++ ++ assert_equal "Valid\tValue", req['HTTP_DUMMY'] ++ end + end +-- +2.23.0 + diff --git a/rubygem-puma.spec b/rubygem-puma.spec index 82154e039855f8bbc7d67a2f49bc7444fcf714e1..ec3a6f83b61dc15ea01abe4670c7ffbe2d0d050a 100644 --- a/rubygem-puma.spec +++ b/rubygem-puma.spec @@ -2,7 +2,7 @@ %bcond_with ragel Name: rubygem-%{gem_name} Version: 3.12.6 -Release: 2 +Release: 3 Summary: A simple, fast, threaded, and highly concurrent HTTP 1.1 server License: BSD URL: http://puma.io @@ -12,6 +12,10 @@ Source1: https://github.com/puma/%{gem_name}/archive/v%{version}.tar # https://fedoraproject.org/wiki/Packaging:CryptoPolicies Patch0: rubygem-puma-3.6.0-fedora-crypto-policy-cipher-list.patch Patch1: CVE-2021-29509.patch +Patch2: CVE-2021-41136-1.patch +Patch3: CVE-2021-41136-2.patch +Patch4: CVE-2021-41136-3.patch +Patch5: CVE-2021-41136-4.patch BuildRequires: openssl-devel ruby(release) rubygems-devel ruby-devel rubygem(rack) BuildRequires: rubygem(minitest) @@ -34,6 +38,10 @@ Documentation for %{name}. %setup -q -n %{gem_name}-%{version} -b 1 %patch0 -p1 %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 %if %{with ragel} rm -f ext/puma_http11/http11_parser.c @@ -100,6 +108,9 @@ popd %{gem_instdir}/tools %changelog +* Thu Oct 21 2021 houyingchao - 3.12.6-3 +- Fix CVE-2021-41136 + * Mon May 31 2021 wangyue - 3.12.6-2 - Fix CVE-2021-29509