Skip to content

v4.3.7

Choose a tag to compare

@petergoldstein petergoldstein released this 06 Oct 01:42
· 270 commits to main since this release
2154bf5

Security release. Released together with 5.2.2, 5.1.4, 5.0.10, 4.3.7 and 3.2.13: with a namespace, a retried request could read or write a different key (GHSA-m252-9cgf-vx2w); completes the fixes for GHSA-wr87-m4jw-29x5 and GHSA-w39f-xq2m-4g8x from 4.3.6, and fixes regressions from that release. Upgrading is strongly recommended.

Security:

  • Keep the caller's key when retrying a request (GHSA-m252-9cgf-vx2w)
    • With a namespace, a request retried after a transient network error (a timeout, or a connection closed by memcached or a proxy) applied the namespace a second time, so a retried read could return a different key's value and a retried write could overwrite a different key
    • Affects get_with_metadata and fetch_with_lock since 4.1.0 (single-key operations on 4.x aren't affected); fixed in 5.2.2, 5.1.4, 5.0.10 and 4.3.7. Clients without a namespace aren't affected
  • Complete the fix for per-request raw: true on reads (GHSA-wr87-m4jw-29x5)
    • cas and cas! (both protocols) and fetch_with_lock (meta protocol) accepted raw: true but didn't pass it to the read, so the value was still deserialized. They now honor it
    • A read made with raw: true doesn't ask for flags, but a reply carrying them anyway (from a proxy or a hostile server) still had its value deserialized. Meta protocol raw reads now ignore flags in the reply
    • Affects 4.3.6 and earlier; fixed in 5.2.2, 5.1.4, 5.0.10, 4.3.7 and 3.2.13
  • Complete the fork-safety fix (GHSA-w39f-xq2m-4g8x)
    • Fork detection used a pid cache refreshed by a Process._fork hook. When another library's fork hook ran first in the child (connection_pool, loaded before Dalli as in Rails, closes its connections there), Dalli didn't know it was in a forked child and ended the parent's TLS session. It now checks Process.pid
    • 4.3.6's write buffer kept a reference to the caller's value string with the meta protocol, so changing the string before the buffer was sent (for example, reusing one buffer inside a quiet block) changed the bytes sent, losing values or adding commands. The buffer now holds a copy
    • Fixed in 4.3.7 and 3.2.13

Bug fixes:

  • get_with_metadata and fetch_with_lock retried the final error raised when a server is marked down, so with down_retry_delay: 0 they retried an unresponsive server forever. They now retry only retryable errors, like other operations
  • Fix a regression in 4.3.6: a get_multi that didn't finish within socket_timeout counted toward socket_max_failures, so two slow get_multi calls in a row marked a healthy server down. It now just closes the connection
  • Fix a regression in 4.3.6: over TLS, every request buffered in a quiet block was sent as its own TLS record and system call (2.5 times slower for a block of 2000 deletes). Each flush is one write again
  • Handle malformed replies from a broken or hostile server or proxy: a negative value size, a hit with no key, or a hit with no s flag could leave the connection out of step or raise a non-Dalli error
  • With decompressed_max_bytes in effect, data after the end of a compressed value's stream was returned as part of the value. It's now ignored, as without the limit
  • With a digest_class whose digests aren't short hex strings, shortening a long key could loop forever. It now raises ArgumentError

Development:

  • Run the Tests, RuboCop and Profiles workflows on pushes to main and the *-stable branches only, so a pull request's branch isn't tested twice (backport of #1198)