dalli 4.3.3 → 4.3.4
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 +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/dalli/client.rb +16 -0
- data/lib/dalli/protocol/meta/request_formatter.rb +21 -8
- data/lib/dalli/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d296cbb71a7d6d7f57969a942e7270bd3b7145160c2ba4c971426dfbdb352368
|
|
4
|
+
data.tar.gz: 14929b5d79fa9d709dd7ccf5b633a44a91fdb2cbc7139eecaa1687e0e63751db
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 04d254a2ea7d37a29634aab3441634ec660fe430efcdf64e3ae547bd456f53a2d9a0c47eb17ae8b8a5407d0fdd6c811d8e4b681213f5089011b217465265388f
|
|
7
|
+
data.tar.gz: 55928535640b642c258efecfbede5a423638d0a45b1c814b7aaff03af67ae65feb5d344e9ab31fa963c25fcb318a25538c7e6e495dec1ae9e2b85c6bcfcc06aa
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
Dalli Changelog
|
|
2
2
|
=====================
|
|
3
3
|
|
|
4
|
+
Unreleased
|
|
5
|
+
==========
|
|
6
|
+
|
|
7
|
+
4.3.4
|
|
8
|
+
==========
|
|
9
|
+
|
|
10
|
+
Security:
|
|
11
|
+
|
|
12
|
+
- Fix memcached command injection through numeric arguments with the meta protocol (GHSA-6wmv-xq9m-fmp7)
|
|
13
|
+
- With `protocol: :meta`, the `default` argument of `incr`/`decr`, and `fetch_with_lock`'s `lock_ttl` and `recache_threshold`, were 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
|
+
- These arguments must now be Integers, or Strings 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`, `R`, `T`) to an Integer
|
|
16
|
+
- Thanks to oss-security-shop for the report
|
|
17
|
+
|
|
4
18
|
4.3.3
|
|
5
19
|
==========
|
|
6
20
|
|
data/lib/dalli/client.rb
CHANGED
|
@@ -237,6 +237,8 @@ module Dalli
|
|
|
237
237
|
raise ArgumentError, 'Block is required for fetch_with_lock' unless block_given?
|
|
238
238
|
|
|
239
239
|
raise_unless_meta_protocol!
|
|
240
|
+
validate_integer!(:lock_ttl, lock_ttl)
|
|
241
|
+
validate_integer!(:recache_threshold, recache_threshold)
|
|
240
242
|
|
|
241
243
|
key = key.to_s
|
|
242
244
|
key = @key_manager.validate_key(key)
|
|
@@ -402,6 +404,8 @@ module Dalli
|
|
|
402
404
|
##
|
|
403
405
|
# Incr adds the given amount to the counter on the memcached server.
|
|
404
406
|
# Amt must be a positive integer value.
|
|
407
|
+
# Default, if given, must be an Integer (or a String of decimal digits);
|
|
408
|
+
# anything else raises ArgumentError.
|
|
405
409
|
#
|
|
406
410
|
# If default is nil, the counter must already exist or the operation
|
|
407
411
|
# will fail and will return nil. Otherwise this method will return
|
|
@@ -414,6 +418,7 @@ module Dalli
|
|
|
414
418
|
# If the value already exists, it must have been set with raw: true
|
|
415
419
|
def incr(key, amt = 1, ttl = nil, default = nil)
|
|
416
420
|
check_positive!(amt)
|
|
421
|
+
validate_integer!(:default, default)
|
|
417
422
|
|
|
418
423
|
perform(:incr, key, amt.to_i, ttl_or_default(ttl), default)
|
|
419
424
|
end
|
|
@@ -421,6 +426,8 @@ module Dalli
|
|
|
421
426
|
##
|
|
422
427
|
# Decr subtracts the given amount from the counter on the memcached server.
|
|
423
428
|
# Amt must be a positive integer value.
|
|
429
|
+
# Default, if given, must be an Integer (or a String of decimal digits);
|
|
430
|
+
# anything else raises ArgumentError.
|
|
424
431
|
#
|
|
425
432
|
# memcached counters are unsigned and cannot hold negative values. Calling
|
|
426
433
|
# decr on a counter which is 0 will just return 0.
|
|
@@ -436,6 +443,7 @@ module Dalli
|
|
|
436
443
|
# If the value already exists, it must have been set with raw: true
|
|
437
444
|
def decr(key, amt = 1, ttl = nil, default = nil)
|
|
438
445
|
check_positive!(amt)
|
|
446
|
+
validate_integer!(:default, default)
|
|
439
447
|
|
|
440
448
|
perform(:decr, key, amt.to_i, ttl_or_default(ttl), default)
|
|
441
449
|
end
|
|
@@ -577,6 +585,14 @@ module Dalli
|
|
|
577
585
|
raise ArgumentError, "Positive values only: #{amt}" if amt.negative?
|
|
578
586
|
end
|
|
579
587
|
|
|
588
|
+
# Numeric arguments that become meta protocol flags (GHSA-6wmv-xq9m-fmp7).
|
|
589
|
+
# Checked before the request starts so a bad value raises a clean
|
|
590
|
+
# ArgumentError, instead of Protocol::Base#request logging it as
|
|
591
|
+
# unexpected and closing the connection.
|
|
592
|
+
def validate_integer!(name, value)
|
|
593
|
+
Dalli::Protocol::Meta::RequestFormatter.integer_flag(name, value) unless value.nil?
|
|
594
|
+
end
|
|
595
|
+
|
|
580
596
|
def cas_core(key, always_set, ttl = nil, req_options = nil)
|
|
581
597
|
(value, cas) = perform(:cas, key)
|
|
582
598
|
return if value.nil? && !always_set
|
|
@@ -45,10 +45,11 @@ module Dalli
|
|
|
45
45
|
cmd << (skip_flags ? ' v' : ' v f') if value
|
|
46
46
|
cmd << ' c' if return_cas
|
|
47
47
|
cmd << ' b' if base64
|
|
48
|
-
cmd << " T#{ttl}" if ttl
|
|
48
|
+
cmd << " T#{integer_flag(:ttl, ttl)}" if ttl
|
|
49
49
|
cmd << ' k q s' if quiet # Return the key in the response if quiet
|
|
50
|
-
cmd << " N#{vivify_ttl}" if vivify_ttl # Thundering herd: vivify on miss
|
|
51
|
-
|
|
50
|
+
cmd << " N#{integer_flag(:vivify_ttl, vivify_ttl)}" if vivify_ttl # Thundering herd: vivify on miss
|
|
51
|
+
# Thundering herd: win recache if TTL below threshold
|
|
52
|
+
cmd << " R#{integer_flag(:recache_ttl, recache_ttl)}" if recache_ttl
|
|
52
53
|
cmd << ' h' if return_hit_status # Return hit status (0 or 1)
|
|
53
54
|
cmd << ' l' if return_last_access # Return seconds since last access
|
|
54
55
|
cmd << ' u' if skip_lru_bump # Don't bump LRU or update access stats
|
|
@@ -61,7 +62,7 @@ module Dalli
|
|
|
61
62
|
cmd << ' b' if base64
|
|
62
63
|
cmd << " F#{bitflags}" if bitflags
|
|
63
64
|
cmd << cas_string(cas)
|
|
64
|
-
cmd << " T#{ttl}" if ttl
|
|
65
|
+
cmd << " T#{integer_flag(:ttl, ttl)}" if ttl
|
|
65
66
|
cmd << " M#{mode_to_token(mode)}"
|
|
66
67
|
cmd << ' q' if quiet
|
|
67
68
|
cmd << TERMINATOR
|
|
@@ -74,7 +75,7 @@ module Dalli
|
|
|
74
75
|
cmd = "md #{key}"
|
|
75
76
|
cmd << ' b' if base64
|
|
76
77
|
cmd << cas_string(cas)
|
|
77
|
-
cmd << " T#{ttl}" if ttl
|
|
78
|
+
cmd << " T#{integer_flag(:ttl, ttl)}" if ttl
|
|
78
79
|
cmd << ' I' if stale # Mark stale instead of deleting
|
|
79
80
|
cmd << ' q' if quiet
|
|
80
81
|
cmd + TERMINATOR
|
|
@@ -83,10 +84,10 @@ module Dalli
|
|
|
83
84
|
def self.meta_arithmetic(key:, delta:, initial:, incr: true, cas: nil, ttl: nil, base64: false, quiet: false)
|
|
84
85
|
cmd = "ma #{key} v"
|
|
85
86
|
cmd << ' b' if base64
|
|
86
|
-
cmd << " D#{delta}" if delta
|
|
87
|
-
cmd << " J#{initial}" if initial
|
|
87
|
+
cmd << " D#{integer_flag(:delta, delta)}" if delta
|
|
88
|
+
cmd << " J#{integer_flag(:initial, initial)}" if initial
|
|
88
89
|
# Always set a TTL if an initial value is specified
|
|
89
|
-
cmd << " N#{ttl
|
|
90
|
+
cmd << " N#{ttl ? integer_flag(:ttl, ttl) : 0}" if ttl || initial
|
|
90
91
|
cmd << cas_string(cas)
|
|
91
92
|
cmd << ' q' if quiet
|
|
92
93
|
cmd << " M#{incr ? 'I' : 'D'}"
|
|
@@ -136,6 +137,18 @@ module Dalli
|
|
|
136
137
|
end
|
|
137
138
|
end
|
|
138
139
|
|
|
140
|
+
# Numeric flag values are written straight into the command line, so a
|
|
141
|
+
# value that isn't an integer -- e.g. a String carrying CRLF -- would let
|
|
142
|
+
# the caller inject further memcached commands (GHSA-6wmv-xq9m-fmp7).
|
|
143
|
+
# Converting to Integer means only digits ever reach the wire. Strings
|
|
144
|
+
# are parsed as base 10 so "010" means 10, as memcached would read it,
|
|
145
|
+
# rather than octal 8.
|
|
146
|
+
def self.integer_flag(name, value)
|
|
147
|
+
value.is_a?(String) ? Integer(value, 10) : Integer(value)
|
|
148
|
+
rescue ArgumentError, TypeError, FloatDomainError
|
|
149
|
+
raise ArgumentError, "#{name} must be an Integer, got #{value.inspect}"
|
|
150
|
+
end
|
|
151
|
+
|
|
139
152
|
def self.cas_string(cas)
|
|
140
153
|
cas = parse_to_64_bit_int(cas, nil)
|
|
141
154
|
cas.nil? || cas.zero? ? '' : " C#{cas}"
|
data/lib/dalli/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dalli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.3.
|
|
4
|
+
version: 4.3.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter M. Goldstein
|
|
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
94
|
version: '0'
|
|
95
95
|
requirements: []
|
|
96
|
-
rubygems_version: 4.0.
|
|
96
|
+
rubygems_version: 4.0.21
|
|
97
97
|
specification_version: 4
|
|
98
98
|
summary: High performance memcached client for Ruby
|
|
99
99
|
test_files: []
|