From: dormando <dormando@rydia.net>
Date: Sun, 21 May 2017 21:49:54 -0700
Subject: Don't overflow item refcount on get
Origin: https://github.com/memcached/memcached/commit/a8c4a82787b8b6c256d61bd5c42fb7f92d1bae00
Bug-Debian: https://bugs.debian.org/894404
Bug: https://github.com/memcached/memcached/issues/271
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2018-1000127

Counts as a miss if the refcount is too high. ASCII multigets are the only
time refcounts can be held for so long.

doing a dirty read of refcount. is aligned.

trying to avoid adding an extra refcount branch for all calls of item_get due
to performance. might be able to move it in there after logging refactoring
simplifies some of the branches.
[carnil: backport to 1.4.21: item_get does not have third and fourth argument prior
         to 1.4.35, upstream commit e87ab394f383acd43076ee1127f1b403882263db, and
         prior to 1.4.26, upstream commit 6895d23e48c6359402066a74c812b3f14be05100]
---
 memcached.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

--- a/memcached.c
+++ b/memcached.c
@@ -2855,6 +2855,16 @@ static void process_stat(conn *c, token_
     }
 }
 
+#define IT_REFCOUNT_LIMIT 60000
+static inline item* limited_get(char *key, size_t nkey) {
+    item *it = item_get(key, nkey);
+    if (it && it->refcount > IT_REFCOUNT_LIMIT) {
+        item_remove(it);
+        it = NULL;
+    }
+    return it;
+}
+
 /* ntokens is overwritten here... shrug.. */
 static inline void process_get_command(conn *c, token_t *tokens, size_t ntokens, bool return_cas) {
     char *key;
@@ -2879,7 +2889,7 @@ static inline void process_get_command(c
                 return;
             }
 
-            it = item_get(key, nkey);
+            it = limited_get(key, nkey);
             if (settings.detail_enabled) {
                 stats_prefix_record_get(key, nkey, NULL != it);
             }
