puma 4.3.0 → 4.3.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: f2ba02cb19976145aa1824079a79d468fad878ca58bdb902f60a58b184049714
4
- data.tar.gz: fcfa744db7db86e4acfbfb3d14659ec4aefa86ec249f6105ea7c54d97e361e97
3
+ metadata.gz: d378ab70a4eac21fe4bf571b95b655d6cbc590b2b91ac323f849986bf8f7ad6c
4
+ data.tar.gz: 1b288cc39f5d80119dde26e844490e572b5f1043060060a1a1d70180743123c3
5
5
  SHA512:
6
- metadata.gz: 875da8dd65d1c85f3912988c0b8b371fcfe1ef2cc99dbb9d4108c2141c2a0427a3db2cca684e82f5b955c564785d3e49f3723aeb64264d76cc4395ec7da2815c
7
- data.tar.gz: 7460c59d0ec3d2c1733fafd35a33c434385da60b70e325f6c85aeeb2ccdea25e07c2b16f7f08f7cc14cccdf44780d5d5f98b1581fb3565e3557dbfb844e4a332
6
+ metadata.gz: b63ddad40bdeae9c86d62af5bf044238e273cbf8e95ff944d7b0a736dd39532dfe3b562a77c97b14f86d8e3f916b7cb94ccdbf898e75c4088d075d20e83744d5
7
+ data.tar.gz: abc975210626407c096848540f068a9731ecdc5191327b3ad87355ef4b88b6ac2605ccc7e31ca5398cd787cf9a34efdffc501afe61a2542cc322768af7b26830
data/History.md CHANGED
@@ -1,10 +1,28 @@
1
- ## Master
2
-
3
- * Features
4
- * Your feature goes here (#Github Number)
1
+ ## 4.3.6 / 2020-09-05
5
2
 
6
3
  * Bugfixes
7
- * Your bugfix goes here (#Github Number)
4
+ * Explicitly include ctype.h to fix compilation warning and build error on macOS with Xcode 12 (#2304)
5
+ * Don't require json at boot (#2269)
6
+
7
+ ## 4.3.4/4.3.5 and 3.12.5/3.12.6 / 2020-05-22
8
+
9
+ Each patchlevel release contains a separate security fix. We recommend simply upgrading to 4.3.5/3.12.6.
10
+
11
+ ## 4.3.3 and 3.12.4 / 2020-02-28
12
+ * Bugfixes
13
+ * Fix: Fixes a problem where we weren't splitting headers correctly on newlines (#2132)
14
+ * Security
15
+ * Fix: Prevent HTTP Response splitting via CR in early hints.
16
+
17
+ ## 4.3.2 and 3.12.3 / 2020-02-27
18
+
19
+ * Security
20
+ * Fix: Prevent HTTP Response splitting via CR/LF in header values. CVE-2020-5247.
21
+
22
+ ## 4.3.1 and 3.12.2 / 2019-12-05
23
+
24
+ * Security
25
+ * Fix: a poorly-behaved client could use keepalive requests to monopolize Puma's reactor and create a denial of service attack. CVE-2019-16770.
8
26
 
9
27
  ## 4.3.0 / 2019-11-07
10
28
 
@@ -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
  }
@@ -10,6 +10,7 @@
10
10
  #include "ext_help.h"
11
11
  #include <assert.h>
12
12
  #include <string.h>
13
+ #include <ctype.h>
13
14
  #include "http11_parser.h"
14
15
 
15
16
  #ifndef MANAGED_STRINGS
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
4
-
5
3
  module Puma
6
4
  module App
7
5
  # Check out {#call}'s source code to see what actions this web application
@@ -19,6 +17,10 @@ module Puma
19
17
  return rack_response(403, 'Invalid auth token', 'text/plain')
20
18
  end
21
19
 
20
+ if env['PATH_INFO'] =~ /\/(gc-stats|stats|thread-backtraces)$/
21
+ require 'json'
22
+ end
23
+
22
24
  case env['PATH_INFO']
23
25
  when /\/stop$/
24
26
  @cli.stop
@@ -285,8 +285,16 @@ module Puma
285
285
 
286
286
  te = @env[TRANSFER_ENCODING2]
287
287
 
288
- if te && CHUNKED.casecmp(te) == 0
289
- return setup_chunked_body(body)
288
+ if te
289
+ if te.include?(",")
290
+ te.split(",").each do |part|
291
+ if CHUNKED.casecmp(part.strip) == 0
292
+ return setup_chunked_body(body)
293
+ end
294
+ end
295
+ elsif CHUNKED.casecmp(te) == 0
296
+ return setup_chunked_body(body)
297
+ end
290
298
  end
291
299
 
292
300
  @chunked_body = false
@@ -100,7 +100,7 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "4.3.0".freeze
103
+ PUMA_VERSION = VERSION = "4.3.6".freeze
104
104
  CODE_NAME = "Mysterious Traveller".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
@@ -466,6 +466,8 @@ module Puma
466
466
  clean_thread_locals = @options[:clean_thread_locals]
467
467
  close_socket = true
468
468
 
469
+ requests = 0
470
+
469
471
  while true
470
472
  case handle_request(client, buffer)
471
473
  when false
@@ -479,7 +481,19 @@ module Puma
479
481
 
480
482
  ThreadPool.clean_thread_locals if clean_thread_locals
481
483
 
482
- unless client.reset(@status == :run)
484
+ requests += 1
485
+
486
+ check_for_more_data = @status == :run
487
+
488
+ if requests >= MAX_FAST_INLINE
489
+ # This will mean that reset will only try to use the data it already
490
+ # has buffered and won't try to read more data. What this means is that
491
+ # every client, independent of their request speed, gets treated like a slow
492
+ # one once every MAX_FAST_INLINE requests.
493
+ check_for_more_data = false
494
+ end
495
+
496
+ unless client.reset(check_for_more_data)
483
497
  close_socket = false
484
498
  client.set_timeout @persistent_timeout
485
499
  @reactor.add client
@@ -643,6 +657,7 @@ module Puma
643
657
  headers.each_pair do |k, vs|
644
658
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
645
659
  vs.to_s.split(NEWLINE).each do |v|
660
+ next if possible_header_injection?(v)
646
661
  fast_write client, "#{k}: #{v}\r\n"
647
662
  end
648
663
  else
@@ -657,6 +672,37 @@ module Puma
657
672
  }
658
673
  end
659
674
 
675
+ # Fixup any headers with , in the name to have _ now. We emit
676
+ # headers with , in them during the parse phase to avoid ambiguity
677
+ # with the - to _ conversion for critical headers. But here for
678
+ # compatibility, we'll convert them back. This code is written to
679
+ # avoid allocation in the common case (ie there are no headers
680
+ # with , in their names), that's why it has the extra conditionals.
681
+
682
+ to_delete = nil
683
+ to_add = nil
684
+
685
+ env.each do |k,v|
686
+ if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
687
+ if to_delete
688
+ to_delete << k
689
+ else
690
+ to_delete = [k]
691
+ end
692
+
693
+ unless to_add
694
+ to_add = {}
695
+ end
696
+
697
+ to_add[k.gsub(",", "_")] = v
698
+ end
699
+ end
700
+
701
+ if to_delete
702
+ to_delete.each { |k| env.delete(k) }
703
+ env.merge! to_add
704
+ end
705
+
660
706
  # A rack extension. If the app writes #call'ables to this
661
707
  # array, we will invoke them when the request is done.
662
708
  #
@@ -744,6 +790,7 @@ module Puma
744
790
  headers.each do |k, vs|
745
791
  case k.downcase
746
792
  when CONTENT_LENGTH2
793
+ next if possible_header_injection?(vs)
747
794
  content_length = vs
748
795
  next
749
796
  when TRANSFER_ENCODING
@@ -756,6 +803,7 @@ module Puma
756
803
 
757
804
  if vs.respond_to?(:to_s) && !vs.to_s.empty?
758
805
  vs.to_s.split(NEWLINE).each do |v|
806
+ next if possible_header_injection?(v)
759
807
  lines.append k, colon, v, line_ending
760
808
  end
761
809
  else
@@ -1026,5 +1074,10 @@ module Puma
1026
1074
  def shutting_down?
1027
1075
  @status == :stop || @status == :restart
1028
1076
  end
1077
+
1078
+ def possible_header_injection?(header_value)
1079
+ HTTP_INJECTION_REGEX =~ header_value.to_s
1080
+ end
1081
+ private :possible_header_injection?
1029
1082
  end
1030
1083
  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: 4.3.0
4
+ version: 4.3.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-11-07 00:00:00.000000000 Z
11
+ date: 2020-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -121,7 +121,7 @@ licenses:
121
121
  metadata:
122
122
  msys2_mingw_dependencies: openssl
123
123
  changelog_uri: https://github.com/puma/puma/blob/master/History.md
124
- post_install_message:
124
+ post_install_message:
125
125
  rdoc_options: []
126
126
  require_paths:
127
127
  - lib
@@ -136,8 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
136
  - !ruby/object:Gem::Version
137
137
  version: '0'
138
138
  requirements: []
139
- rubygems_version: 3.0.3
140
- signing_key:
139
+ rubygems_version: 3.1.2
140
+ signing_key:
141
141
  specification_version: 4
142
142
  summary: Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for
143
143
  Ruby/Rack applications