dalli 3.2.8 → 3.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7d8b3dd9e76a224d876f901dc44c3cf8016326209df3efc7fe522053a4a3c22
4
- data.tar.gz: 0ced058a6a170cadd4b74268de5417c4a1e700baf5767fc8f260db9477e2b735
3
+ metadata.gz: 2fe56d2ea432b05cde81f7b4c5e3017fc8e11788526cd3dbecbaede2e11c1659
4
+ data.tar.gz: 450380fe328c475a93b32d4b1cca10fef1d33065d13bed32e1126276621c2e54
5
5
  SHA512:
6
- metadata.gz: 3e316a4d60c3327cecec46a0a34c52536130199124035c375bf1933676d85fbf09e99a985ae44faf4e27b0fb1f8b8faef1656a812e6bdfc387406c5e18874461
7
- data.tar.gz: bce3e0e41c280e99889bea6835c1b2f701cbcb5e4f398203ae2b4d6ebc05cdc505ee5955365715f8e00441d69701ceac84de37a98eac8581d003d1ab411a33e9
6
+ metadata.gz: ccdbfa346efdf6a09ab53fbd4e44179b298028e348716780b5356d909270fce2fa5fdf66f00579703ab9e0a15dde4b699faf483b5fadb016cff434b85b99011a
7
+ data.tar.gz: 3c312e4303bf6b076b20fa28a73277b3975396af12cbee42e3c1cceaab9fde3cb679422f3301a0c3c06a784f3706c704d1e181207bb107b245db2683d7f0c690
data/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ Dalli Changelog
4
4
  Unreleased
5
5
  ==========
6
6
 
7
+ 3.2.9
8
+ ==========
9
+
10
+ Security:
11
+
12
+ - Fix memcached command injection through the `incr`/`decr` default with the meta protocol (GHSA-6wmv-xq9m-fmp7)
13
+ - With `protocol: :meta`, the `default` argument of `incr`/`decr` was written into the command without conversion, so a String containing CRLF injected additional memcached commands (e.g. `set`, `flush_all`) on the connection. The default binary protocol is not affected
14
+ - `default` must now be an Integer, or a String of decimal digits; anything else raises `ArgumentError` before a request is sent
15
+ - As defense in depth, the meta `RequestFormatter` now converts every numeric flag it writes (`D`, `J`, `N`, `T`) to an Integer
16
+ - Thanks to oss-security-shop for the report
17
+
7
18
  3.2.8
8
19
  ==========
9
20
 
data/lib/dalli/client.rb CHANGED
@@ -257,6 +257,8 @@ module Dalli
257
257
  ##
258
258
  # Incr adds the given amount to the counter on the memcached server.
259
259
  # Amt must be a positive integer value.
260
+ # Default, if given, must be an Integer (or a String of decimal digits);
261
+ # anything else raises ArgumentError.
260
262
  #
261
263
  # If default is nil, the counter must already exist or the operation
262
264
  # will fail and will return nil. Otherwise this method will return
@@ -269,6 +271,7 @@ module Dalli
269
271
  # If the value already exists, it must have been set with raw: true
270
272
  def incr(key, amt = 1, ttl = nil, default = nil)
271
273
  check_positive!(amt)
274
+ validate_integer!(:default, default)
272
275
 
273
276
  perform(:incr, key, amt.to_i, ttl_or_default(ttl), default)
274
277
  end
@@ -276,6 +279,8 @@ module Dalli
276
279
  ##
277
280
  # Decr subtracts the given amount from the counter on the memcached server.
278
281
  # Amt must be a positive integer value.
282
+ # Default, if given, must be an Integer (or a String of decimal digits);
283
+ # anything else raises ArgumentError.
279
284
  #
280
285
  # memcached counters are unsigned and cannot hold negative values. Calling
281
286
  # decr on a counter which is 0 will just return 0.
@@ -291,6 +296,7 @@ module Dalli
291
296
  # If the value already exists, it must have been set with raw: true
292
297
  def decr(key, amt = 1, ttl = nil, default = nil)
293
298
  check_positive!(amt)
299
+ validate_integer!(:default, default)
294
300
 
295
301
  perform(:decr, key, amt.to_i, ttl_or_default(ttl), default)
296
302
  end
@@ -373,6 +379,14 @@ module Dalli
373
379
  raise ArgumentError, "Positive values only: #{amt}" if amt.negative?
374
380
  end
375
381
 
382
+ # Numeric arguments that become meta protocol flags (GHSA-6wmv-xq9m-fmp7).
383
+ # Checked before the request starts so a bad value raises a clean
384
+ # ArgumentError, instead of Protocol::Base#request logging it as
385
+ # unexpected and closing the connection.
386
+ def validate_integer!(name, value)
387
+ Dalli::Protocol::Meta::RequestFormatter.integer_flag(name, value) unless value.nil?
388
+ end
389
+
376
390
  def cas_core(key, always_set, ttl = nil, req_options = nil)
377
391
  (value, cas) = perform(:cas, key)
378
392
  return if value.nil? && !always_set
@@ -21,7 +21,7 @@ module Dalli
21
21
  cmd << ' v f' if value
22
22
  cmd << ' c' if return_cas
23
23
  cmd << ' b' if base64
24
- cmd << " T#{ttl}" if ttl
24
+ cmd << " T#{integer_flag(:ttl, ttl)}" if ttl
25
25
  cmd << ' k q s' if quiet # Return the key in the response if quiet
26
26
  cmd + TERMINATOR
27
27
  end
@@ -32,7 +32,7 @@ module Dalli
32
32
  cmd << ' b' if base64
33
33
  cmd << " F#{bitflags}" if bitflags
34
34
  cmd << cas_string(cas)
35
- cmd << " T#{ttl}" if ttl
35
+ cmd << " T#{integer_flag(:ttl, ttl)}" if ttl
36
36
  cmd << " M#{mode_to_token(mode)}"
37
37
  cmd << ' q' if quiet
38
38
  cmd << TERMINATOR
@@ -44,7 +44,7 @@ module Dalli
44
44
  cmd = "md #{key}"
45
45
  cmd << ' b' if base64
46
46
  cmd << cas_string(cas)
47
- cmd << " T#{ttl}" if ttl
47
+ cmd << " T#{integer_flag(:ttl, ttl)}" if ttl
48
48
  cmd << ' q' if quiet
49
49
  cmd + TERMINATOR
50
50
  end
@@ -52,10 +52,10 @@ module Dalli
52
52
  def self.meta_arithmetic(key:, delta:, initial:, incr: true, cas: nil, ttl: nil, base64: false, quiet: false)
53
53
  cmd = "ma #{key} v"
54
54
  cmd << ' b' if base64
55
- cmd << " D#{delta}" if delta
56
- cmd << " J#{initial}" if initial
55
+ cmd << " D#{integer_flag(:delta, delta)}" if delta
56
+ cmd << " J#{integer_flag(:initial, initial)}" if initial
57
57
  # Always set a TTL if an initial value is specified
58
- cmd << " N#{ttl || 0}" if ttl || initial
58
+ cmd << " N#{ttl ? integer_flag(:ttl, ttl) : 0}" if ttl || initial
59
59
  cmd << cas_string(cas)
60
60
  cmd << ' q' if quiet
61
61
  cmd << " M#{incr ? 'I' : 'D'}"
@@ -104,6 +104,18 @@ module Dalli
104
104
  end
105
105
  # rubocop:enable Metrics/MethodLength
106
106
 
107
+ # Numeric flag values are written straight into the command line, so a
108
+ # value that isn't an integer -- e.g. a String carrying CRLF -- would let
109
+ # the caller inject further memcached commands (GHSA-6wmv-xq9m-fmp7).
110
+ # Converting to Integer means only digits ever reach the wire. Strings
111
+ # are parsed as base 10 so "010" means 10, as memcached would read it,
112
+ # rather than octal 8.
113
+ def self.integer_flag(name, value)
114
+ value.is_a?(String) ? Integer(value, 10) : Integer(value)
115
+ rescue ArgumentError, TypeError, FloatDomainError
116
+ raise ArgumentError, "#{name} must be an Integer, got #{value.inspect}"
117
+ end
118
+
107
119
  def self.cas_string(cas)
108
120
  cas = parse_to_64_bit_int(cas, nil)
109
121
  cas.nil? || cas.zero? ? '' : " C#{cas}"
data/lib/dalli/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dalli
4
- VERSION = '3.2.8'
4
+ VERSION = '3.2.9'
5
5
 
6
6
  MIN_SUPPORTED_MEMCACHED_VERSION = '1.4'
7
7
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dalli
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.8
4
+ version: 3.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter M. Goldstein
8
8
  - Mike Perham
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-02-12 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies: []
14
13
  description: High performance memcached client for Ruby
15
14
  email:
@@ -62,7 +61,6 @@ metadata:
62
61
  bug_tracker_uri: https://github.com/petergoldstein/dalli/issues
63
62
  changelog_uri: https://github.com/petergoldstein/dalli/blob/main/CHANGELOG.md
64
63
  rubygems_mfa_required: 'true'
65
- post_install_message:
66
64
  rdoc_options: []
67
65
  require_paths:
68
66
  - lib
@@ -77,8 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
75
  - !ruby/object:Gem::Version
78
76
  version: '0'
79
77
  requirements: []
80
- rubygems_version: 3.5.6
81
- signing_key:
78
+ rubygems_version: 4.0.21
82
79
  specification_version: 4
83
80
  summary: High performance memcached client for Ruby
84
81
  test_files: []