puma 3.12.1 → 3.12.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d0e3b5d74ced5d332fa04832c60b4b8b9c16514f3441cefea046d6ca4948025
4
- data.tar.gz: 9462d0f9e3357c2b245f194b43281e5f8e5ebf0ee981e7658a938d880e3e4404
3
+ metadata.gz: da843833fd17b4bb2283f4c5161a1aa9367a6613455b8fbf31bae49393db4f80
4
+ data.tar.gz: bd9259270bd27f8421827c66e7f515044f51a7672c3dc755836d2a6b1240e84d
5
5
  SHA512:
6
- metadata.gz: 19ffe686429f3271d947e8fbc73c1e55113a0ad22eea2a194c80abac60cf675ea4162675f99d641e18e91d1d4270eae80644ccab5667ad263dfb32eb0b3075f2
7
- data.tar.gz: 40876e43164a6103bcfc560a6034f4fb2215d0da39d84cb5d53f961da64a8d8e41e3f239f1a7886a0f13c6e6a1357608a54efc009517e1b3b2afc72c4a570b8d
6
+ metadata.gz: 74d807145c97b7714c04ebf7858af57b1cdf00e87217b8a88428494718893f7670ffd27216c31164f57bd96984cd8e79f3c7f856d39c1b54c192965fe8ecdec8
7
+ data.tar.gz: e0616e41dceddc3b8aad69a5baab5b49007053d151bf2689de173495f3160900269bab94c539a47fe2bbdd2db1aab98a0df8177ece857a06bea6261c5d37a704
data/History.md CHANGED
@@ -4,7 +4,24 @@
4
4
 
5
5
  * x bugfixes
6
6
 
7
- ## 3.12.1 / 2019-01-08
7
+
8
+ ## 4.3.3 and 3.12.4 / 2020-02-28
9
+ * Bugfixes
10
+ * Fix: Fixes a problem where we weren't splitting headers correctly on newlines (#2132)
11
+ * Security
12
+ * Fix: Prevent HTTP Response splitting via CR in early hints.
13
+
14
+ ## 4.3.2 and 3.12.3 / 2020-02-27
15
+
16
+ * Security
17
+ * Fix: Prevent HTTP Response splitting via CR/LF in header values. CVE-2020-5247.
18
+
19
+ ## 4.3.1 and 3.12.2 / 2019-12-05
20
+
21
+ * Security
22
+ * Fix: a poorly-behaved client could use keepalive requests to monopolize Puma's reactor and create a denial of service attack. CVE-2019-16770.
23
+
24
+ ## 3.12.1 / 2019-03-19
8
25
 
9
26
  * 1 features
10
27
  * Internal strings are frozen (#1649)
Binary file
Binary file
@@ -14,12 +14,14 @@
14
14
 
15
15
  /*
16
16
  * capitalizes all lower-case ASCII characters,
17
- * converts dashes to underscores.
17
+ * converts dashes to underscores, and underscores to commas.
18
18
  */
19
19
  static void snake_upcase_char(char *c)
20
20
  {
21
21
  if (*c >= 'a' && *c <= 'z')
22
22
  *c &= ~0x20;
23
+ else if (*c == '_')
24
+ *c = ',';
23
25
  else if (*c == '-')
24
26
  *c = '_';
25
27
  }
@@ -12,12 +12,14 @@
12
12
 
13
13
  /*
14
14
  * capitalizes all lower-case ASCII characters,
15
- * converts dashes to underscores.
15
+ * converts dashes to underscores, and underscores to commas.
16
16
  */
17
17
  static void snake_upcase_char(char *c)
18
18
  {
19
19
  if (*c >= 'a' && *c <= 'z')
20
20
  *c &= ~0x20;
21
+ else if (*c == '_')
22
+ *c = ',';
21
23
  else if (*c == '-')
22
24
  *c = '_';
23
25
  }
data/lib/puma/client.rb CHANGED
@@ -244,8 +244,16 @@ module Puma
244
244
 
245
245
  te = @env[TRANSFER_ENCODING2]
246
246
 
247
- if te && CHUNKED.casecmp(te) == 0
248
- return setup_chunked_body(body)
247
+ if te
248
+ if te.include?(",")
249
+ te.split(",").each do |part|
250
+ if CHUNKED.casecmp(part.strip) == 0
251
+ return setup_chunked_body(body)
252
+ end
253
+ end
254
+ elsif CHUNKED.casecmp(te) == 0
255
+ return setup_chunked_body(body)
256
+ end
249
257
  end
250
258
 
251
259
  @chunked_body = false
data/lib/puma/const.rb CHANGED
@@ -100,7 +100,7 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "3.12.1".freeze
103
+ PUMA_VERSION = VERSION = "3.12.6".freeze
104
104
  CODE_NAME = "Llamas in Pajamas".freeze
105
105
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
106
 
@@ -118,6 +118,13 @@ module Puma
118
118
  # sending data back
119
119
  WRITE_TIMEOUT = 10
120
120
 
121
+ # How many requests to attempt inline before sending a client back to
122
+ # the reactor to be subject to normal ordering. The idea here is that
123
+ # we amortize the cost of going back to the reactor for a well behaved
124
+ # but very "greedy" client across 10 requests. This prevents a not
125
+ # well behaved client from monopolizing the thread forever.
126
+ MAX_FAST_INLINE = 10
127
+
121
128
  # The original URI requested by the client.
122
129
  REQUEST_URI= 'REQUEST_URI'.freeze
123
130
  REQUEST_PATH = 'REQUEST_PATH'.freeze
@@ -221,6 +228,7 @@ module Puma
221
228
  COLON = ": ".freeze
222
229
 
223
230
  NEWLINE = "\n".freeze
231
+ HTTP_INJECTION_REGEX = /[\r\n]/.freeze
224
232
 
225
233
  HIJACK_P = "rack.hijack?".freeze
226
234
  HIJACK = "rack.hijack".freeze
data/lib/puma/server.rb CHANGED
@@ -470,6 +470,8 @@ module Puma
470
470
  clean_thread_locals = @options[:clean_thread_locals]
471
471
  close_socket = true
472
472
 
473
+ requests = 0
474
+
473
475
  while true
474
476
  case handle_request(client, buffer)
475
477
  when false
@@ -483,7 +485,19 @@ module Puma
483
485
 
484
486
  ThreadPool.clean_thread_locals if clean_thread_locals
485
487
 
486
- unless client.reset(@status == :run)
488
+ requests += 1
489
+
490
+ check_for_more_data = @status == :run
491
+
492
+ if requests >= MAX_FAST_INLINE
493
+ # This will mean that reset will only try to use the data it already
494
+ # has buffered and won't try to read more data. What this means is that
495
+ # every client, independent of their request speed, gets treated like a slow
496
+ # one once every MAX_FAST_INLINE requests.
497
+ check_for_more_data = false
498
+ end
499
+
500
+ unless client.reset(check_for_more_data)
487
501
  close_socket = false
488
502
  client.set_timeout @persistent_timeout
489
503
  @reactor.add client
@@ -639,6 +653,7 @@ module Puma
639
653
  headers.each_pair do |k, vs|
640
654
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
641
655
  vs.to_s.split(NEWLINE).each do |v|
656
+ next if possible_header_injection?(v)
642
657
  fast_write client, "#{k}: #{v}\r\n"
643
658
  end
644
659
  else
@@ -650,6 +665,37 @@ module Puma
650
665
  }
651
666
  end
652
667
 
668
+ # Fixup any headers with , in the name to have _ now. We emit
669
+ # headers with , in them during the parse phase to avoid ambiguity
670
+ # with the - to _ conversion for critical headers. But here for
671
+ # compatibility, we'll convert them back. This code is written to
672
+ # avoid allocation in the common case (ie there are no headers
673
+ # with , in their names), that's why it has the extra conditionals.
674
+
675
+ to_delete = nil
676
+ to_add = nil
677
+
678
+ env.each do |k,v|
679
+ if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
680
+ if to_delete
681
+ to_delete << k
682
+ else
683
+ to_delete = [k]
684
+ end
685
+
686
+ unless to_add
687
+ to_add = {}
688
+ end
689
+
690
+ to_add[k.gsub(",", "_")] = v
691
+ end
692
+ end
693
+
694
+ if to_delete
695
+ to_delete.each { |k| env.delete(k) }
696
+ env.merge! to_add
697
+ end
698
+
653
699
  # A rack extension. If the app writes #call'ables to this
654
700
  # array, we will invoke them when the request is done.
655
701
  #
@@ -737,6 +783,7 @@ module Puma
737
783
  headers.each do |k, vs|
738
784
  case k.downcase
739
785
  when CONTENT_LENGTH2
786
+ next if possible_header_injection?(vs)
740
787
  content_length = vs
741
788
  next
742
789
  when TRANSFER_ENCODING
@@ -749,6 +796,7 @@ module Puma
749
796
 
750
797
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
751
798
  vs.to_s.split(NEWLINE).each do |v|
799
+ next if possible_header_injection?(v)
752
800
  lines.append k, colon, v, line_ending
753
801
  end
754
802
  else
@@ -1015,5 +1063,10 @@ module Puma
1015
1063
  def shutting_down?
1016
1064
  @status == :stop || @status == :restart
1017
1065
  end
1066
+
1067
+ def possible_header_injection?(header_value)
1068
+ HTTP_INJECTION_REGEX =~ header_value.to_s
1069
+ end
1070
+ private :possible_header_injection?
1018
1071
  end
1019
1072
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.12.1
4
+ version: 3.12.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-19 00:00:00.000000000 Z
11
+ date: 2020-05-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server
14
14
  for Ruby/Rack applications. Puma is intended for use in both development and production
@@ -108,7 +108,7 @@ licenses:
108
108
  - BSD-3-Clause
109
109
  metadata:
110
110
  msys2_mingw_dependencies: openssl
111
- post_install_message:
111
+ post_install_message:
112
112
  rdoc_options: []
113
113
  require_paths:
114
114
  - lib
@@ -123,9 +123,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  requirements: []
126
- rubyforge_project:
127
- rubygems_version: 2.7.6
128
- signing_key:
126
+ rubygems_version: 3.0.3
127
+ signing_key:
129
128
  specification_version: 4
130
129
  summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
131
130
  Ruby/Rack applications