Repository navigation
v5.2.3
Security release. Released together with 5.2.3, 5.1.5, 5.0.11, 4.3.8 and 3.2.14: with the meta protocol, a counter that incr or decr created with an initial value for a key containing spaces, CR/LF or non-ASCII characters could let a crafted key forge the value of another key in a multi-get (GHSA-r47x-6p6r-mvcp). Upgrading is strongly recommended. This release also includes the bug fixes and the new connect_timeout option below.
Security:
- Don't rely on memcached's auto-create for keys that need base64 encoding (GHSA-r47x-6p6r-mvcp)
- memcached stores an item made by auto-create (
mawithN/J, ormgwithN) for a base64-encoded key without its binary-key flag, and later replies name the item by its raw key bytes. A key containing spaces or CR/LF could then make a multi-get read the replies after it as different ones incranddecrwith an initial value now create such counters with an add instead. Return values are unchanged- The new
verify_reply_keysoption makesget_multi,get_multi_casandget_multi_with_metadataignore replies for keys they didn't request, which guards against items created by older Dalli versions or other clients until memcached is upgraded. It's off by default, since it costs a multi-get about 15% - Affects the meta protocol since 3.2.0; fixed in 5.2.3, 5.1.5, 5.0.11, 4.3.8 and 3.2.14. memcached 1.6.45 and earlier still name these items by their raw key bytes
- memcached stores an item made by auto-create (
Bug fixes:
get_multi_with_metadataand itsCacheResultadapter now retry transient network errors and raiseDalli::NetworkErroron terminal failures instead of returning misses or partial results (#1222, @jaideeppyne)- A per-request
raw: truewrite no longer compresses the value (#1213)- Values at or above the compression threshold (4 KB by default) were compressed and flagged even with
raw: true. Raw reads ignore flags, so reading them back withraw: truereturned the compressed bytes - Raw values are now stored exactly as given. Callers that pass
raw: truewithoutcompress: falsestore large values uncompressed; Rails'MemCacheStorepassescompress: falseand isn't affected
- Values at or above the compression threshold (4 KB by default) were compressed and flagged even with
- Fix
casandcas!edge cases, and makeflushattempt every server (#1214)cas!on a missing key used an unconditional set, so a value another client created while the block ran was overwritten. It now adds the key and returnsfalseif another client got there first- With
cache_nils: true,castreated a storednilas a miss and didn't call the block - The docs now say what
casandcas!return on success: the new CAS value, nottrue. The return values are unchanged flushstopped at the first server that raised, so later servers weren't flushed. It now flushes every server it can reach, then raises the first error
- Handle failed TLS handshakes like other connection failures, and warn when TLS verification is off (#1215)
- A failed or timed-out handshake left the TCP socket open until GC and raised
OpenSSL::SSL::SSLErrordirectly, so the server was never marked down. The socket is now closed, and the error goes through the usual retry andsocket_max_failureshandling, raisingDalli::NetworkError(orDalli::RingErroronce no server is available) - Certificate and hostname checks come only from the
ssl_contextyou pass, and a bareOpenSSL::SSL::SSLContext.newchecks neither. Dalli now logs a warning once per process whenverify_modedoesn't includeVERIFY_PEERorverify_hostnameis false; see the new TLS section in the README
- A failed or timed-out handshake left the TCP socket open until GC and raised
- Connection and configuration fixes (#1216)
memcached://URIs with a bracketed IPv6 host (memcached://[::1]:11211) now connect- A server weight below 1 raises
ArgumentError. Before, a ring where every weight was 0 raisedFloatDomainError - A reply line longer than 8 KiB without a CRLF, or one cut short by the connection closing, is now a network error that closes the connection. Before, the line had no length limit
- On CRuby, DNS resolution is now limited by
socket_timeout(resolv_timeout:) as well as the connect
Dalli::Client.newno longer modifies the options hash it's given, and accepts a frozen one (#1217)value_max_bytesnow counts the key and memcached's per-item overhead (#1217)- memcached's
-Ilimit covers the whole item, not only the value. A value of exactly 1 MB passed Dalli's check and then failed in memcached withDalli::ServerError, whichquietblocks andset_multisilently discarded - Dalli now checks value + key + 63 bytes, the overhead measured on memcached 1.6, and raises
Dalli::ValueOverMaxSizebefore sending. A customvalue_max_bytesis now that much stricter - A String
value_max_bytesis converted to an Integer instead of raising on every set
- memcached's
Rack::Session::Dallifixes (#1217)- It no longer requires the
connection_poolgem unlesspool_sizeorpool_timeoutis given pool_sizeandpool_timeoutare no longer passed toDalli::Client, and the options hash isn't modified- A failed session delete is logged as a warning, not only when
$VERBOSEis set
- It no longer requires the
- One value that can't be stored no longer discards other buffered writes (#1218)
- A value that raised
Dalli::MarshalErrororDalli::ValueOverMaxSizeclosed the connection, which dropped writes still buffered from the samequietblock orset_multi. Multi-serverset_multidid this without raising - Both
set_multipaths now store every other key, skip the bad one, and then raise. Single-serverset_multiused to store nothing - When single-server
set_multifailed to marshal a value, the error log included every value in the batch. It now lists only the keys
- A value that raised
Rack::Session::Dalli's 401 for a session deleted mid-request is now a valid Rack response (#1220)- When a session is deleted while a request is using it (for example, by a logout in another request), the store still returns 401 instead of writing the session back. The 401 now has a
content-typeand expires the session cookie, so the browser stops sending the dead session ID - The app's response body is now closed, as the Rack spec requires. Before, it was dropped without
close - The app has already run when the 401 is returned, so its side effects have happened. This is documented in the README
- When a session is deleted while a request is using it (for example, by a logout in another request), the store still returns 401 instead of writing the session back. The 401 now has a
Improvements:
- Add a
connect_timeoutoption to set a separate timeout for DNS resolution and TCP/UNIX socket connects (including reconnects); it defaults tosocket_timeout. TLS handshakes continue to usesocket_timeout(#1221, @underwoo16)