Repository navigation
Conversation
Memcached::SERIALIZER_PHPSER (memcached.serializer=phpser) stores arrays, objects, and null with phpser and flags them with the new MEMC_VAL_IS_PHPSER type, as the igbinary serializer does. Scalars stay native. The module requires phpser and refuses to start unless phpser is 0.9.0 or later and exports the expected API version. Build with --enable-memcached-phpser; PECL and PIE expose the same option.
Items are decoded by the type in their stored flags, not by the client's serializer, so anyone who can write to the memcached servers can store an item flagged as PHP-serialized and have unserialize() run on it. When the serializer is phpser and phpser.key is set, strings, booleans, null, arrays, and objects are now written as signed phpser values; integers and floats stay native so increment() and decrement() keep working. Reads accept only phpser items, which phpser verifies before decoding, and native integers and floats. Every other type reads back as false with a warning, the same result as a value that fails to unserialize. The check sits in s_memcached_result_to_zval(), which every read path goes through, and runs before decompression. append() and prepend() are refused in this mode, as they are with compression, because they would break the signature. A non-empty key shorter than phpser accepts also enables the gate; phpser then rejects every phpser value.
Round trips with and without phpser.key, the stored type of each value, counters, append/prepend refusal, and user flags. Attack tests write items with forged flags over the raw protocol and through a PHP-serializer client (PHP-serialized and igbinary gadgets, compressed gadgets, strings, booleans, JSON, msgpack, unsigned, tampered, truncated, wrong-key, and wrong-context phpser) and check that each reads back as false and that no object is constructed, through get, getByKey, getMulti, getDelayed, fetch, fetchAll, result callbacks, and read-through callbacks. A short phpser.key fails closed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
Memcached::SERIALIZER_PHPSER, backed by the C API in phpser 0.9.0+ (ext/phpser/php_phpser_api.h). phpser is my extension. Wiring follows igbinary:--enable-memcached-phpser,HAVE_MEMCACHED_PHPSER,ZEND_MOD_REQUIRED("phpser"),memcached.serializer = phpser,setOption,config.w32, and the PECL/PIE option. phpredis merged the same serializer in phpredis/phpredis#2959.Two benefits: speed (19-85% faster encode, 26-92% faster decode than igbinary on phpser's ten-case ARM benchmark) and signing. With
phpser.keyset, each value carries an HMAC-SHA256 tag bound to the key and amemcachedcontext, checked before any decode work.php-memcached picks the decoder from the item's stored flags, not the client's serializer, so anyone who can write to memcached can store an item flagged
MEMC_VAL_IS_SERIALIZEDand get it unserialized. With phpser andphpser.keyset:increment()/decrement()work.falsewith a warning, checked before decompression.append()/prepend()are refused, as with compression.Without
phpser.key, phpser behaves like igbinary.One side effect: a binary-protocol
increment()with an initial value creates the item with string flags, so keyedget()returnsfalsefor it. Documented in the README.