summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-oe/recipes-extended/redis/redis/0001-src-Do-not-reset-FINAL_LIBS.patch10
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32626.patch148
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32627-CVE-2021-32628.patch873
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32675.patch129
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32687.patch67
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch257
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-32762.patch68
-rw-r--r--meta-oe/recipes-extended/redis/redis/CVE-2021-41099.patch47
-rw-r--r--meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29477.patch35
-rw-r--r--meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29478.patch42
-rw-r--r--meta-oe/recipes-extended/redis/redis/fix-CVE-2021-32625.patch61
-rw-r--r--meta-oe/recipes-extended/redis/redis_6.2.6.bb (renamed from meta-oe/recipes-extended/redis/redis_6.2.2.bb)15
12 files changed, 6 insertions, 1746 deletions
diff --git a/meta-oe/recipes-extended/redis/redis/0001-src-Do-not-reset-FINAL_LIBS.patch b/meta-oe/recipes-extended/redis/redis/0001-src-Do-not-reset-FINAL_LIBS.patch
index b5c4133e31..43d86094d5 100644
--- a/meta-oe/recipes-extended/redis/redis/0001-src-Do-not-reset-FINAL_LIBS.patch
+++ b/meta-oe/recipes-extended/redis/redis/0001-src-Do-not-reset-FINAL_LIBS.patch
@@ -1,4 +1,4 @@
1From 97584e1eb78dc18599534b47b6670c20c63f5ee2 Mon Sep 17 00:00:00 2001 1From aff8b278bd36085036d302027bc215483ad7f32b Mon Sep 17 00:00:00 2001
2From: Khem Raj <raj.khem@gmail.com> 2From: Khem Raj <raj.khem@gmail.com>
3Date: Tue, 10 Sep 2019 20:04:26 -0700 3Date: Tue, 10 Sep 2019 20:04:26 -0700
4Subject: [PATCH] src: Do not reset FINAL_LIBS 4Subject: [PATCH] src: Do not reset FINAL_LIBS
@@ -15,10 +15,10 @@ Signed-off-by: Khem Raj <raj.khem@gmail.com>
15 1 file changed, 1 insertion(+), 1 deletion(-) 15 1 file changed, 1 insertion(+), 1 deletion(-)
16 16
17diff --git a/src/Makefile b/src/Makefile 17diff --git a/src/Makefile b/src/Makefile
18index 7f7c625..c71dd3b 100644 18index 7a7168c..d0680e8 100644
19--- a/src/Makefile 19--- a/src/Makefile
20+++ b/src/Makefile 20+++ b/src/Makefile
21@@ -75,7 +75,7 @@ endif 21@@ -91,7 +91,7 @@ endif
22 22
23 FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS) 23 FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
24 FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG) 24 FINAL_LDFLAGS=$(LDFLAGS) $(REDIS_LDFLAGS) $(DEBUG)
@@ -26,7 +26,7 @@ index 7f7c625..c71dd3b 100644
26+FINAL_LIBS+=-lm 26+FINAL_LIBS+=-lm
27 DEBUG=-g -ggdb 27 DEBUG=-g -ggdb
28 28
29 # Linux ARM needs -latomic at linking time 29 # Linux ARM32 needs -latomic at linking time
30-- 30--
312.23.0 312.17.1
32 32
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32626.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32626.patch
deleted file mode 100644
index 0cfc12b3d9..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-32626.patch
+++ /dev/null
@@ -1,148 +0,0 @@
1From 6ce827254484fd850240549c98c74bca77980cc0 Mon Sep 17 00:00:00 2001
2From: "meir@redislabs.com" <meir@redislabs.com>
3Date: Sun, 13 Jun 2021 14:27:18 +0300
4Subject: [PATCH] Fix invalid memory write on lua stack overflow
5 {CVE-2021-32626}
6MIME-Version: 1.0
7Content-Type: text/plain; charset=UTF-8
8Content-Transfer-Encoding: 8bit
9
10When LUA call our C code, by default, the LUA stack has room for 20
11elements. In most cases, this is more than enough but sometimes it's not
12and the caller must verify the LUA stack size before he pushes elements.
13
14On 3 places in the code, there was no verification of the LUA stack size.
15On specific inputs this missing verification could have lead to invalid
16memory write:
171. On 'luaReplyToRedisReply', one might return a nested reply that will
18 explode the LUA stack.
192. On 'redisProtocolToLuaType', the Redis reply might be deep enough
20   to explode the LUA stack (notice that currently there is no such
21   command in Redis that returns such a nested reply, but modules might
22   do it)
233. On 'ldbRedis', one might give a command with enough arguments to
24   explode the LUA stack (all the arguments will be pushed to the LUA
25   stack)
26
27This commit is solving all those 3 issues by calling 'lua_checkstack' and
28verify that there is enough room in the LUA stack to push elements. In
29case 'lua_checkstack' returns an error (there is not enough room in the
30LUA stack and it's not possible to increase the stack), we will do the
31following:
321. On 'luaReplyToRedisReply', we will return an error to the user.
332. On 'redisProtocolToLuaType' we will exit with panic (we assume this
34 scenario is rare because it can only happen with a module).
353. On 'ldbRedis', we return an error.
36
37CVE: CVE-2021-32626
38Upstream-Status: Backport[https://github.com/redis/redis/commit/666ed7facf4524bf6d19b11b20faa2cf93fdf591]
39
40Signed-off-by: Changqing Li <changqing.li@windriver.com>
41---
42 src/scripting.c | 41 +++++++++++++++++++++++++++++++++++++++++
43 1 file changed, 41 insertions(+)
44
45diff --git a/src/scripting.c b/src/scripting.c
46index 299e608..81c88fb 100644
47--- a/src/scripting.c
48+++ b/src/scripting.c
49@@ -128,6 +128,16 @@ void sha1hex(char *digest, char *script, size_t len) {
50 */
51
52 char *redisProtocolToLuaType(lua_State *lua, char* reply) {
53+
54+ if (!lua_checkstack(lua, 5)) {
55+ /*
56+ * Increase the Lua stack if needed, to make sure there is enough room
57+ * to push 5 elements to the stack. On failure, exit with panic.
58+         * Notice that we need, in the worst case, 5 elements because redisProtocolToLuaType_Aggregate
59+         * might push 5 elements to the Lua stack.*/
60+ serverPanic("lua stack limit reach when parsing redis.call reply");
61+ }
62+
63 char *p = reply;
64
65 switch(*p) {
66@@ -220,6 +230,11 @@ char *redisProtocolToLuaType_Aggregate(lua_State *lua, char *reply, int atype) {
67 if (atype == '%') {
68 p = redisProtocolToLuaType(lua,p);
69 } else {
70+ if (!lua_checkstack(lua, 1)) {
71+ /* Notice that here we need to check the stack again because the recursive
72+ * call to redisProtocolToLuaType might have use the room allocated in the stack */
73+ serverPanic("lua stack limit reach when parsing redis.call reply");
74+ }
75 lua_pushboolean(lua,1);
76 }
77 lua_settable(lua,-3);
78@@ -339,6 +354,17 @@ void luaSortArray(lua_State *lua) {
79 /* Reply to client 'c' converting the top element in the Lua stack to a
80 * Redis reply. As a side effect the element is consumed from the stack. */
81 void luaReplyToRedisReply(client *c, lua_State *lua) {
82+
83+ if (!lua_checkstack(lua, 4)) {
84+ /* Increase the Lua stack if needed to make sure there is enough room
85+ * to push 4 elements to the stack. On failure, return error.
86+         * Notice that we need, in the worst case, 4 elements because returning a map might
87+ * require push 4 elements to the Lua stack.*/
88+ addReplyErrorFormat(c, "reached lua stack limit");
89+ lua_pop(lua,1); // pop the element from the stack
90+ return;
91+ }
92+
93 int t = lua_type(lua,-1);
94
95 switch(t) {
96@@ -362,6 +388,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
97 * field. */
98
99 /* Handle error reply. */
100+ // we took care of the stack size on function start
101 lua_pushstring(lua,"err");
102 lua_gettable(lua,-2);
103 t = lua_type(lua,-1);
104@@ -404,6 +431,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
105 if (t == LUA_TTABLE) {
106 int maplen = 0;
107 void *replylen = addReplyDeferredLen(c);
108+ /* we took care of the stack size on function start */
109 lua_pushnil(lua); /* Use nil to start iteration. */
110 while (lua_next(lua,-2)) {
111 /* Stack now: table, key, value */
112@@ -426,6 +454,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
113 if (t == LUA_TTABLE) {
114 int setlen = 0;
115 void *replylen = addReplyDeferredLen(c);
116+ /* we took care of the stack size on function start */
117 lua_pushnil(lua); /* Use nil to start iteration. */
118 while (lua_next(lua,-2)) {
119 /* Stack now: table, key, true */
120@@ -445,6 +474,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) {
121 void *replylen = addReplyDeferredLen(c);
122 int j = 1, mbulklen = 0;
123 while(1) {
124+ /* we took care of the stack size on function start */
125 lua_pushnumber(lua,j++);
126 lua_gettable(lua,-2);
127 t = lua_type(lua,-1);
128@@ -2546,6 +2576,17 @@ void ldbEval(lua_State *lua, sds *argv, int argc) {
129 void ldbRedis(lua_State *lua, sds *argv, int argc) {
130 int j, saved_rc = server.lua_replicate_commands;
131
132+ if (!lua_checkstack(lua, argc + 1)) {
133+ /* Increase the Lua stack if needed to make sure there is enough room
134+ * to push 'argc + 1' elements to the stack. On failure, return error.
135+         * Notice that we need, in worst case, 'argc + 1' elements because we push all the arguments
136+         * given by the user (without the first argument) and we also push the 'redis' global table and
137+         * 'redis.call' function so:
138+         * (1 (redis table)) + (1 (redis.call function)) + (argc - 1 (all arguments without the first)) = argc + 1*/
139+ ldbLogRedisReply("max lua stack reached");
140+ return;
141+ }
142+
143 lua_getglobal(lua,"redis");
144 lua_pushstring(lua,"call");
145 lua_gettable(lua,-2); /* Stack: redis, redis.call */
146--
1472.17.1
148
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32627-CVE-2021-32628.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32627-CVE-2021-32628.patch
deleted file mode 100644
index 3c60a3e678..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-32627-CVE-2021-32628.patch
+++ /dev/null
@@ -1,873 +0,0 @@
1From 2775a3526e3e8bb040e72995231632c801977395 Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Thu, 3 Jun 2021 12:10:02 +0300
4Subject: [PATCH] Fix ziplist and listpack overflows and truncations
5 (CVE-2021-32627, CVE-2021-32628)
6
7- fix possible heap corruption in ziplist and listpack resulting by trying to
8 allocate more than the maximum size of 4GB.
9- prevent ziplist (hash and zset) from reaching size of above 1GB, will be
10 converted to HT encoding, that's not a useful size.
11- prevent listpack (stream) from reaching size of above 1GB.
12- XADD will start a new listpack if the new record may cause the previous
13 listpack to grow over 1GB.
14- XADD will respond with an error if a single stream record is over 1GB
15- List type (ziplist in quicklist) was truncating strings that were over 4GB,
16 now it'll respond with an error.
17
18CVE: CVE-2021-32627,CVE-2021-32628
19Upstream-Status: Backport[https://github.com/redis/redis/commit/f6a40570fa63d5afdd596c78083d754081d80ae3]
20
21Signed-off-by: Changqing Li <changqing.li@windriver.com>
22
23---
24 src/geo.c | 5 +-
25 src/listpack.c | 2 +-
26 src/module.c | 6 +-
27 src/quicklist.c | 16 +++-
28 src/rdb.c | 45 +++++++----
29 src/server.h | 2 +-
30 src/t_hash.c | 13 +++-
31 src/t_list.c | 29 +++++++
32 src/t_stream.c | 48 +++++++++---
33 src/t_zset.c | 62 +++++++++------
34 src/ziplist.c | 17 ++++-
35 src/ziplist.h | 1 +
36 tests/unit/violations.tcl | 156 ++++++++++++++++++++++++++++++++++++++
37 13 files changed, 341 insertions(+), 61 deletions(-)
38 create mode 100644 tests/unit/violations.tcl
39
40diff --git a/src/geo.c b/src/geo.c
41index 7c75738a2..893f78a7e 100644
42--- a/src/geo.c
43+++ b/src/geo.c
44@@ -770,7 +770,7 @@ void georadiusGeneric(client *c, int srcKeyIndex, int flags) {
45 robj *zobj;
46 zset *zs;
47 int i;
48- size_t maxelelen = 0;
49+ size_t maxelelen = 0, totelelen = 0;
50
51 if (returned_items) {
52 zobj = createZsetObject();
53@@ -785,13 +785,14 @@ void georadiusGeneric(client *c, int srcKeyIndex, int flags) {
54 size_t elelen = sdslen(gp->member);
55
56 if (maxelelen < elelen) maxelelen = elelen;
57+ totelelen += elelen;
58 znode = zslInsert(zs->zsl,score,gp->member);
59 serverAssert(dictAdd(zs->dict,gp->member,&znode->score) == DICT_OK);
60 gp->member = NULL;
61 }
62
63 if (returned_items) {
64- zsetConvertToZiplistIfNeeded(zobj,maxelelen);
65+ zsetConvertToZiplistIfNeeded(zobj,maxelelen,totelelen);
66 setKey(c,c->db,storekey,zobj);
67 decrRefCount(zobj);
68 notifyKeyspaceEvent(NOTIFY_ZSET,flags & GEOSEARCH ? "geosearchstore" : "georadiusstore",storekey,
69diff --git a/src/listpack.c b/src/listpack.c
70index ee256bad3..27622d4a5 100644
71--- a/src/listpack.c
72+++ b/src/listpack.c
73@@ -313,7 +313,7 @@ int lpEncodeGetType(unsigned char *ele, uint32_t size, unsigned char *intenc, ui
74 } else {
75 if (size < 64) *enclen = 1+size;
76 else if (size < 4096) *enclen = 2+size;
77- else *enclen = 5+size;
78+ else *enclen = 5+(uint64_t)size;
79 return LP_ENCODING_STRING;
80 }
81 }
82diff --git a/src/module.c b/src/module.c
83index bf6580a60..adca9dc9c 100644
84--- a/src/module.c
85+++ b/src/module.c
86@@ -3319,6 +3319,7 @@ int RM_HashGet(RedisModuleKey *key, int flags, ...) {
87 * - EDOM if the given ID was 0-0 or not greater than all other IDs in the
88 * stream (only if the AUTOID flag is unset)
89 * - EFBIG if the stream has reached the last possible ID
90+ * - ERANGE if the elements are too large to be stored.
91 */
92 int RM_StreamAdd(RedisModuleKey *key, int flags, RedisModuleStreamID *id, RedisModuleString **argv, long numfields) {
93 /* Validate args */
94@@ -3362,8 +3363,9 @@ int RM_StreamAdd(RedisModuleKey *key, int flags, RedisModuleStreamID *id, RedisM
95 use_id_ptr = &use_id;
96 }
97 if (streamAppendItem(s, argv, numfields, &added_id, use_id_ptr) == C_ERR) {
98- /* ID not greater than all existing IDs in the stream */
99- errno = EDOM;
100+ /* Either the ID not greater than all existing IDs in the stream, or
101+ * the elements are too large to be stored. either way, errno is already
102+ * set by streamAppendItem. */
103 return REDISMODULE_ERR;
104 }
105 /* Postponed signalKeyAsReady(). Done implicitly by moduleCreateEmptyKey()
106diff --git a/src/quicklist.c b/src/quicklist.c
107index 5a1e41dcc..a9f8b43b1 100644
108--- a/src/quicklist.c
109+++ b/src/quicklist.c
110@@ -45,11 +45,16 @@
111 #define REDIS_STATIC static
112 #endif
113
114-/* Optimization levels for size-based filling */
115+/* Optimization levels for size-based filling.
116+ * Note that the largest possible limit is 16k, so even if each record takes
117+ * just one byte, it still won't overflow the 16 bit count field. */
118 static const size_t optimization_level[] = {4096, 8192, 16384, 32768, 65536};
119
120 /* Maximum size in bytes of any multi-element ziplist.
121- * Larger values will live in their own isolated ziplists. */
122+ * Larger values will live in their own isolated ziplists.
123+ * This is used only if we're limited by record count. when we're limited by
124+ * size, the maximum limit is bigger, but still safe.
125+ * 8k is a recommended / default size limit */
126 #define SIZE_SAFETY_LIMIT 8192
127
128 /* Minimum ziplist size in bytes for attempting compression. */
129@@ -444,6 +449,8 @@ REDIS_STATIC int _quicklistNodeAllowInsert(const quicklistNode *node,
130 unsigned int new_sz = node->sz + sz + ziplist_overhead;
131 if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(new_sz, fill)))
132 return 1;
133+ /* when we return 1 above we know that the limit is a size limit (which is
134+ * safe, see comments next to optimization_level and SIZE_SAFETY_LIMIT) */
135 else if (!sizeMeetsSafetyLimit(new_sz))
136 return 0;
137 else if ((int)node->count < fill)
138@@ -463,6 +470,8 @@ REDIS_STATIC int _quicklistNodeAllowMerge(const quicklistNode *a,
139 unsigned int merge_sz = a->sz + b->sz - 11;
140 if (likely(_quicklistNodeSizeMeetsOptimizationRequirement(merge_sz, fill)))
141 return 1;
142+ /* when we return 1 above we know that the limit is a size limit (which is
143+ * safe, see comments next to optimization_level and SIZE_SAFETY_LIMIT) */
144 else if (!sizeMeetsSafetyLimit(merge_sz))
145 return 0;
146 else if ((int)(a->count + b->count) <= fill)
147@@ -482,6 +491,7 @@ REDIS_STATIC int _quicklistNodeAllowMerge(const quicklistNode *a,
148 * Returns 1 if new head created. */
149 int quicklistPushHead(quicklist *quicklist, void *value, size_t sz) {
150 quicklistNode *orig_head = quicklist->head;
151+ assert(sz < UINT32_MAX); /* TODO: add support for quicklist nodes that are sds encoded (not zipped) */
152 if (likely(
153 _quicklistNodeAllowInsert(quicklist->head, quicklist->fill, sz))) {
154 quicklist->head->zl =
155@@ -505,6 +515,7 @@ int quicklistPushHead(quicklist *quicklist, void *value, size_t sz) {
156 * Returns 1 if new tail created. */
157 int quicklistPushTail(quicklist *quicklist, void *value, size_t sz) {
158 quicklistNode *orig_tail = quicklist->tail;
159+ assert(sz < UINT32_MAX); /* TODO: add support for quicklist nodes that are sds encoded (not zipped) */
160 if (likely(
161 _quicklistNodeAllowInsert(quicklist->tail, quicklist->fill, sz))) {
162 quicklist->tail->zl =
163@@ -847,6 +858,7 @@ REDIS_STATIC void _quicklistInsert(quicklist *quicklist, quicklistEntry *entry,
164 int fill = quicklist->fill;
165 quicklistNode *node = entry->node;
166 quicklistNode *new_node = NULL;
167+ assert(sz < UINT32_MAX); /* TODO: add support for quicklist nodes that are sds encoded (not zipped) */
168
169 if (!node) {
170 /* we have no reference node, so let's create only node in the list */
171diff --git a/src/rdb.c b/src/rdb.c
172index 53f67a72e..5456c1d80 100644
173--- a/src/rdb.c
174+++ b/src/rdb.c
175@@ -1625,7 +1625,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
176 } else if (rdbtype == RDB_TYPE_ZSET_2 || rdbtype == RDB_TYPE_ZSET) {
177 /* Read list/set value. */
178 uint64_t zsetlen;
179- size_t maxelelen = 0;
180+ size_t maxelelen = 0, totelelen = 0;
181 zset *zs;
182
183 if ((zsetlen = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
184@@ -1665,6 +1665,7 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
185
186 /* Don't care about integer-encoded strings. */
187 if (sdslen(sdsele) > maxelelen) maxelelen = sdslen(sdsele);
188+ totelelen += sdslen(sdsele);
189
190 znode = zslInsert(zs->zsl,score,sdsele);
191 if (dictAdd(zs->dict,sdsele,&znode->score) != DICT_OK) {
192@@ -1677,8 +1678,11 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
193
194 /* Convert *after* loading, since sorted sets are not stored ordered. */
195 if (zsetLength(o) <= server.zset_max_ziplist_entries &&
196- maxelelen <= server.zset_max_ziplist_value)
197- zsetConvert(o,OBJ_ENCODING_ZIPLIST);
198+ maxelelen <= server.zset_max_ziplist_value &&
199+ ziplistSafeToAdd(NULL, totelelen))
200+ {
201+ zsetConvert(o,OBJ_ENCODING_ZIPLIST);
202+ }
203 } else if (rdbtype == RDB_TYPE_HASH) {
204 uint64_t len;
205 int ret;
206@@ -1731,21 +1735,30 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
207 }
208 }
209
210- /* Add pair to ziplist */
211- o->ptr = ziplistPush(o->ptr, (unsigned char*)field,
212- sdslen(field), ZIPLIST_TAIL);
213- o->ptr = ziplistPush(o->ptr, (unsigned char*)value,
214- sdslen(value), ZIPLIST_TAIL);
215-
216 /* Convert to hash table if size threshold is exceeded */
217 if (sdslen(field) > server.hash_max_ziplist_value ||
218- sdslen(value) > server.hash_max_ziplist_value)
219+ sdslen(value) > server.hash_max_ziplist_value ||
220+ !ziplistSafeToAdd(o->ptr, sdslen(field)+sdslen(value)))
221 {
222- sdsfree(field);
223- sdsfree(value);
224 hashTypeConvert(o, OBJ_ENCODING_HT);
225+ ret = dictAdd((dict*)o->ptr, field, value);
226+ if (ret == DICT_ERR) {
227+ rdbReportCorruptRDB("Duplicate hash fields detected");
228+ if (dupSearchDict) dictRelease(dupSearchDict);
229+ sdsfree(value);
230+ sdsfree(field);
231+ decrRefCount(o);
232+ return NULL;
233+ }
234 break;
235 }
236+
237+ /* Add pair to ziplist */
238+ o->ptr = ziplistPush(o->ptr, (unsigned char*)field,
239+ sdslen(field), ZIPLIST_TAIL);
240+ o->ptr = ziplistPush(o->ptr, (unsigned char*)value,
241+ sdslen(value), ZIPLIST_TAIL);
242+
243 sdsfree(field);
244 sdsfree(value);
245 }
246@@ -1858,12 +1871,11 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
247 while ((zi = zipmapNext(zi, &fstr, &flen, &vstr, &vlen)) != NULL) {
248 if (flen > maxlen) maxlen = flen;
249 if (vlen > maxlen) maxlen = vlen;
250- zl = ziplistPush(zl, fstr, flen, ZIPLIST_TAIL);
251- zl = ziplistPush(zl, vstr, vlen, ZIPLIST_TAIL);
252
253 /* search for duplicate records */
254 sds field = sdstrynewlen(fstr, flen);
255- if (!field || dictAdd(dupSearchDict, field, NULL) != DICT_OK) {
256+ if (!field || dictAdd(dupSearchDict, field, NULL) != DICT_OK ||
257+ !ziplistSafeToAdd(zl, (size_t)flen + vlen)) {
258 rdbReportCorruptRDB("Hash zipmap with dup elements, or big length (%u)", flen);
259 dictRelease(dupSearchDict);
260 sdsfree(field);
261@@ -1872,6 +1884,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
262 decrRefCount(o);
263 return NULL;
264 }
265+
266+ zl = ziplistPush(zl, fstr, flen, ZIPLIST_TAIL);
267+ zl = ziplistPush(zl, vstr, vlen, ZIPLIST_TAIL);
268 }
269
270 dictRelease(dupSearchDict);
271diff --git a/src/server.h b/src/server.h
272index d9fef9552..07b34c743 100644
273--- a/src/server.h
274+++ b/src/server.h
275@@ -2173,7 +2173,7 @@ unsigned char *zzlFirstInRange(unsigned char *zl, zrangespec *range);
276 unsigned char *zzlLastInRange(unsigned char *zl, zrangespec *range);
277 unsigned long zsetLength(const robj *zobj);
278 void zsetConvert(robj *zobj, int encoding);
279-void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen);
280+void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen, size_t totelelen);
281 int zsetScore(robj *zobj, sds member, double *score);
282 unsigned long zslGetRank(zskiplist *zsl, double score, sds o);
283 int zsetAdd(robj *zobj, double score, sds ele, int in_flags, int *out_flags, double *newscore);
284diff --git a/src/t_hash.c b/src/t_hash.c
285index ea0606fb0..2720fdbc7 100644
286--- a/src/t_hash.c
287+++ b/src/t_hash.c
288@@ -39,17 +39,22 @@
289 * as their string length can be queried in constant time. */
290 void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {
291 int i;
292+ size_t sum = 0;
293
294 if (o->encoding != OBJ_ENCODING_ZIPLIST) return;
295
296 for (i = start; i <= end; i++) {
297- if (sdsEncodedObject(argv[i]) &&
298- sdslen(argv[i]->ptr) > server.hash_max_ziplist_value)
299- {
300+ if (!sdsEncodedObject(argv[i]))
301+ continue;
302+ size_t len = sdslen(argv[i]->ptr);
303+ if (len > server.hash_max_ziplist_value) {
304 hashTypeConvert(o, OBJ_ENCODING_HT);
305- break;
306+ return;
307 }
308+ sum += len;
309 }
310+ if (!ziplistSafeToAdd(o->ptr, sum))
311+ hashTypeConvert(o, OBJ_ENCODING_HT);
312 }
313
314 /* Get the value from a ziplist encoded hash, identified by field.
315diff --git a/src/t_list.c b/src/t_list.c
316index f8ca27458..66c9e3c9d 100644
317--- a/src/t_list.c
318+++ b/src/t_list.c
319@@ -29,6 +29,8 @@
320
321 #include "server.h"
322
323+#define LIST_MAX_ITEM_SIZE ((1ull<<32)-1024)
324+
325 /*-----------------------------------------------------------------------------
326 * List API
327 *----------------------------------------------------------------------------*/
328@@ -224,6 +226,13 @@ robj *listTypeDup(robj *o) {
329 void pushGenericCommand(client *c, int where, int xx) {
330 int j;
331
332+ for (j = 2; j < c->argc; j++) {
333+ if (sdslen(c->argv[j]->ptr) > LIST_MAX_ITEM_SIZE) {
334+ addReplyError(c, "Element too large");
335+ return;
336+ }
337+ }
338+
339 robj *lobj = lookupKeyWrite(c->db, c->argv[1]);
340 if (checkType(c,lobj,OBJ_LIST)) return;
341 if (!lobj) {
342@@ -287,6 +296,11 @@ void linsertCommand(client *c) {
343 return;
344 }
345
346+ if (sdslen(c->argv[4]->ptr) > LIST_MAX_ITEM_SIZE) {
347+ addReplyError(c, "Element too large");
348+ return;
349+ }
350+
351 if ((subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
352 checkType(c,subject,OBJ_LIST)) return;
353
354@@ -354,6 +368,11 @@ void lsetCommand(client *c) {
355 long index;
356 robj *value = c->argv[3];
357
358+ if (sdslen(value->ptr) > LIST_MAX_ITEM_SIZE) {
359+ addReplyError(c, "Element too large");
360+ return;
361+ }
362+
363 if ((getLongFromObjectOrReply(c, c->argv[2], &index, NULL) != C_OK))
364 return;
365
366@@ -576,6 +595,11 @@ void lposCommand(client *c) {
367 int direction = LIST_TAIL;
368 long rank = 1, count = -1, maxlen = 0; /* Count -1: option not given. */
369
370+ if (sdslen(ele->ptr) > LIST_MAX_ITEM_SIZE) {
371+ addReplyError(c, "Element too large");
372+ return;
373+ }
374+
375 /* Parse the optional arguments. */
376 for (int j = 3; j < c->argc; j++) {
377 char *opt = c->argv[j]->ptr;
378@@ -671,6 +695,11 @@ void lremCommand(client *c) {
379 long toremove;
380 long removed = 0;
381
382+ if (sdslen(obj->ptr) > LIST_MAX_ITEM_SIZE) {
383+ addReplyError(c, "Element too large");
384+ return;
385+ }
386+
387 if ((getLongFromObjectOrReply(c, c->argv[2], &toremove, NULL) != C_OK))
388 return;
389
390diff --git a/src/t_stream.c b/src/t_stream.c
391index 2c30faa06..574195ee3 100644
392--- a/src/t_stream.c
393+++ b/src/t_stream.c
394@@ -47,6 +47,12 @@
395 * setting stream_node_max_bytes to a huge number. */
396 #define STREAM_LISTPACK_MAX_PRE_ALLOCATE 4096
397
398+/* Don't let listpacks grow too big, even if the user config allows it.
399+ * doing so can lead to an overflow (trying to store more than 32bit length
400+ * into the listpack header), or actually an assertion since lpInsert
401+ * will return NULL. */
402+#define STREAM_LISTPACK_MAX_SIZE (1<<30)
403+
404 void streamFreeCG(streamCG *cg);
405 void streamFreeNACK(streamNACK *na);
406 size_t streamReplyWithRangeFromConsumerPEL(client *c, stream *s, streamID *start, streamID *end, size_t count, streamConsumer *consumer);
407@@ -433,8 +439,11 @@ void streamGetEdgeID(stream *s, int first, streamID *edge_id)
408 *
409 * The function returns C_OK if the item was added, this is always true
410 * if the ID was generated by the function. However the function may return
411- * C_ERR if an ID was given via 'use_id', but adding it failed since the
412- * current top ID is greater or equal. */
413+ * C_ERR in several cases:
414+ * 1. If an ID was given via 'use_id', but adding it failed since the
415+ * current top ID is greater or equal. errno will be set to EDOM.
416+ * 2. If a size of a single element or the sum of the elements is too big to
417+ * be stored into the stream. errno will be set to ERANGE. */
418 int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_id, streamID *use_id) {
419
420 /* Generate the new entry ID. */
421@@ -448,7 +457,23 @@ int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_
422 * or return an error. Automatically generated IDs might
423 * overflow (and wrap-around) when incrementing the sequence
424 part. */
425- if (streamCompareID(&id,&s->last_id) <= 0) return C_ERR;
426+ if (streamCompareID(&id,&s->last_id) <= 0) {
427+ errno = EDOM;
428+ return C_ERR;
429+ }
430+
431+ /* Avoid overflow when trying to add an element to the stream (listpack
432+ * can only host up to 32bit length sttrings, and also a total listpack size
433+ * can't be bigger than 32bit length. */
434+ size_t totelelen = 0;
435+ for (int64_t i = 0; i < numfields*2; i++) {
436+ sds ele = argv[i]->ptr;
437+ totelelen += sdslen(ele);
438+ }
439+ if (totelelen > STREAM_LISTPACK_MAX_SIZE) {
440+ errno = ERANGE;
441+ return C_ERR;
442+ }
443
444 /* Add the new entry. */
445 raxIterator ri;
446@@ -507,9 +532,10 @@ int streamAppendItem(stream *s, robj **argv, int64_t numfields, streamID *added_
447 * if we need to switch to the next one. 'lp' will be set to NULL if
448 * the current node is full. */
449 if (lp != NULL) {
450- if (server.stream_node_max_bytes &&
451- lp_bytes >= server.stream_node_max_bytes)
452- {
453+ size_t node_max_bytes = server.stream_node_max_bytes;
454+ if (node_max_bytes == 0 || node_max_bytes > STREAM_LISTPACK_MAX_SIZE)
455+ node_max_bytes = STREAM_LISTPACK_MAX_SIZE;
456+ if (lp_bytes + totelelen >= node_max_bytes) {
457 lp = NULL;
458 } else if (server.stream_node_max_entries) {
459 unsigned char *lp_ele = lpFirst(lp);
460@@ -1796,11 +1822,13 @@ void xaddCommand(client *c) {
461 /* Append using the low level function and return the ID. */
462 streamID id;
463 if (streamAppendItem(s,c->argv+field_pos,(c->argc-field_pos)/2,
464- &id, parsed_args.id_given ? &parsed_args.id : NULL)
465- == C_ERR)
466+ &id, parsed_args.id_given ? &parsed_args.id : NULL) == C_ERR)
467 {
468- addReplyError(c,"The ID specified in XADD is equal or smaller than the "
469- "target stream top item");
470+ if (errno == EDOM)
471+ addReplyError(c,"The ID specified in XADD is equal or smaller than "
472+ "the target stream top item");
473+ else
474+ addReplyError(c,"Elements are too large to be stored");
475 return;
476 }
477 addReplyStreamID(c,&id);
478diff --git a/src/t_zset.c b/src/t_zset.c
479index 3b9ebd2bd..2abc1b49b 100644
480--- a/src/t_zset.c
481+++ b/src/t_zset.c
482@@ -1242,15 +1242,18 @@ void zsetConvert(robj *zobj, int encoding) {
483 }
484
485 /* Convert the sorted set object into a ziplist if it is not already a ziplist
486- * and if the number of elements and the maximum element size is within the
487- * expected ranges. */
488-void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen) {
489+ * and if the number of elements and the maximum element size and total elements size
490+ * are within the expected ranges. */
491+void zsetConvertToZiplistIfNeeded(robj *zobj, size_t maxelelen, size_t totelelen) {
492 if (zobj->encoding == OBJ_ENCODING_ZIPLIST) return;
493 zset *zset = zobj->ptr;
494
495 if (zset->zsl->length <= server.zset_max_ziplist_entries &&
496- maxelelen <= server.zset_max_ziplist_value)
497- zsetConvert(zobj,OBJ_ENCODING_ZIPLIST);
498+ maxelelen <= server.zset_max_ziplist_value &&
499+ ziplistSafeToAdd(NULL, totelelen))
500+ {
501+ zsetConvert(zobj,OBJ_ENCODING_ZIPLIST);
502+ }
503 }
504
505 /* Return (by reference) the score of the specified member of the sorted set
506@@ -1370,20 +1373,28 @@ int zsetAdd(robj *zobj, double score, sds ele, int in_flags, int *out_flags, dou
507 }
508 return 1;
509 } else if (!xx) {
510- /* Optimize: check if the element is too large or the list
511+ /* check if the element is too large or the list
512 * becomes too long *before* executing zzlInsert. */
513- zobj->ptr = zzlInsert(zobj->ptr,ele,score);
514- if (zzlLength(zobj->ptr) > server.zset_max_ziplist_entries ||
515- sdslen(ele) > server.zset_max_ziplist_value)
516+ if (zzlLength(zobj->ptr)+1 > server.zset_max_ziplist_entries ||
517+ sdslen(ele) > server.zset_max_ziplist_value ||
518+ !ziplistSafeToAdd(zobj->ptr, sdslen(ele)))
519+ {
520 zsetConvert(zobj,OBJ_ENCODING_SKIPLIST);
521- if (newscore) *newscore = score;
522- *out_flags |= ZADD_OUT_ADDED;
523- return 1;
524+ } else {
525+ zobj->ptr = zzlInsert(zobj->ptr,ele,score);
526+ if (newscore) *newscore = score;
527+ *out_flags |= ZADD_OUT_ADDED;
528+ return 1;
529+ }
530 } else {
531 *out_flags |= ZADD_OUT_NOP;
532 return 1;
533 }
534- } else if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
535+ }
536+
537+ /* Note that the above block handling ziplist would have either returned or
538+ * converted the key to skiplist. */
539+ if (zobj->encoding == OBJ_ENCODING_SKIPLIST) {
540 zset *zs = zobj->ptr;
541 zskiplistNode *znode;
542 dictEntry *de;
543@@ -2361,7 +2372,7 @@ inline static void zunionInterAggregate(double *target, double val, int aggregat
544 }
545 }
546
547-static int zsetDictGetMaxElementLength(dict *d) {
548+static size_t zsetDictGetMaxElementLength(dict *d, size_t *totallen) {
549 dictIterator *di;
550 dictEntry *de;
551 size_t maxelelen = 0;
552@@ -2371,6 +2382,8 @@ static int zsetDictGetMaxElementLength(dict *d) {
553 while((de = dictNext(di)) != NULL) {
554 sds ele = dictGetKey(de);
555 if (sdslen(ele) > maxelelen) maxelelen = sdslen(ele);
556+ if (totallen)
557+ (*totallen) += sdslen(ele);
558 }
559
560 dictReleaseIterator(di);
561@@ -2378,7 +2391,7 @@ static int zsetDictGetMaxElementLength(dict *d) {
562 return maxelelen;
563 }
564
565-static void zdiffAlgorithm1(zsetopsrc *src, long setnum, zset *dstzset, size_t *maxelelen) {
566+static void zdiffAlgorithm1(zsetopsrc *src, long setnum, zset *dstzset, size_t *maxelelen, size_t *totelelen) {
567 /* DIFF Algorithm 1:
568 *
569 * We perform the diff by iterating all the elements of the first set,
570@@ -2426,13 +2439,14 @@ static void zdiffAlgorithm1(zsetopsrc *src, long setnum, zset *dstzset, size_t *
571 znode = zslInsert(dstzset->zsl,zval.score,tmp);
572 dictAdd(dstzset->dict,tmp,&znode->score);
573 if (sdslen(tmp) > *maxelelen) *maxelelen = sdslen(tmp);
574+ (*totelelen) += sdslen(tmp);
575 }
576 }
577 zuiClearIterator(&src[0]);
578 }
579
580
581-static void zdiffAlgorithm2(zsetopsrc *src, long setnum, zset *dstzset, size_t *maxelelen) {
582+static void zdiffAlgorithm2(zsetopsrc *src, long setnum, zset *dstzset, size_t *maxelelen, size_t *totelelen) {
583 /* DIFF Algorithm 2:
584 *
585 * Add all the elements of the first set to the auxiliary set.
586@@ -2486,7 +2500,7 @@ static void zdiffAlgorithm2(zsetopsrc *src, long setnum, zset *dstzset, size_t *
587
588 /* Using this algorithm, we can't calculate the max element as we go,
589 * we have to iterate through all elements to find the max one after. */
590- *maxelelen = zsetDictGetMaxElementLength(dstzset->dict);
591+ *maxelelen = zsetDictGetMaxElementLength(dstzset->dict, totelelen);
592 }
593
594 static int zsetChooseDiffAlgorithm(zsetopsrc *src, long setnum) {
595@@ -2523,14 +2537,14 @@ static int zsetChooseDiffAlgorithm(zsetopsrc *src, long setnum) {
596 return (algo_one_work <= algo_two_work) ? 1 : 2;
597 }
598
599-static void zdiff(zsetopsrc *src, long setnum, zset *dstzset, size_t *maxelelen) {
600+static void zdiff(zsetopsrc *src, long setnum, zset *dstzset, size_t *maxelelen, size_t *totelelen) {
601 /* Skip everything if the smallest input is empty. */
602 if (zuiLength(&src[0]) > 0) {
603 int diff_algo = zsetChooseDiffAlgorithm(src, setnum);
604 if (diff_algo == 1) {
605- zdiffAlgorithm1(src, setnum, dstzset, maxelelen);
606+ zdiffAlgorithm1(src, setnum, dstzset, maxelelen, totelelen);
607 } else if (diff_algo == 2) {
608- zdiffAlgorithm2(src, setnum, dstzset, maxelelen);
609+ zdiffAlgorithm2(src, setnum, dstzset, maxelelen, totelelen);
610 } else if (diff_algo != 0) {
611 serverPanic("Unknown algorithm");
612 }
613@@ -2565,7 +2579,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
614 zsetopsrc *src;
615 zsetopval zval;
616 sds tmp;
617- size_t maxelelen = 0;
618+ size_t maxelelen = 0, totelelen = 0;
619 robj *dstobj;
620 zset *dstzset;
621 zskiplistNode *znode;
622@@ -2701,6 +2715,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
623 tmp = zuiNewSdsFromValue(&zval);
624 znode = zslInsert(dstzset->zsl,score,tmp);
625 dictAdd(dstzset->dict,tmp,&znode->score);
626+ totelelen += sdslen(tmp);
627 if (sdslen(tmp) > maxelelen) maxelelen = sdslen(tmp);
628 }
629 }
630@@ -2737,6 +2752,7 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
631 /* Remember the longest single element encountered,
632 * to understand if it's possible to convert to ziplist
633 * at the end. */
634+ totelelen += sdslen(tmp);
635 if (sdslen(tmp) > maxelelen) maxelelen = sdslen(tmp);
636 /* Update the element with its initial score. */
637 dictSetKey(accumulator, de, tmp);
638@@ -2771,14 +2787,14 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
639 dictReleaseIterator(di);
640 dictRelease(accumulator);
641 } else if (op == SET_OP_DIFF) {
642- zdiff(src, setnum, dstzset, &maxelelen);
643+ zdiff(src, setnum, dstzset, &maxelelen, &totelelen);
644 } else {
645 serverPanic("Unknown operator");
646 }
647
648 if (dstkey) {
649 if (dstzset->zsl->length) {
650- zsetConvertToZiplistIfNeeded(dstobj, maxelelen);
651+ zsetConvertToZiplistIfNeeded(dstobj, maxelelen, totelelen);
652 setKey(c, c->db, dstkey, dstobj);
653 addReplyLongLong(c, zsetLength(dstobj));
654 notifyKeyspaceEvent(NOTIFY_ZSET,
655diff --git a/src/ziplist.c b/src/ziplist.c
656index aae86c1f2..fdc1bb9e1 100644
657--- a/src/ziplist.c
658+++ b/src/ziplist.c
659@@ -267,6 +267,17 @@
660 ZIPLIST_LENGTH(zl) = intrev16ifbe(intrev16ifbe(ZIPLIST_LENGTH(zl))+incr); \
661 }
662
663+/* Don't let ziplists grow over 1GB in any case, don't wanna risk overflow in
664+ * zlbytes*/
665+#define ZIPLIST_MAX_SAFETY_SIZE (1<<30)
666+int ziplistSafeToAdd(unsigned char* zl, size_t add) {
667+ size_t len = zl? ziplistBlobLen(zl): 0;
668+ if (len + add > ZIPLIST_MAX_SAFETY_SIZE)
669+ return 0;
670+ return 1;
671+}
672+
673+
674 /* We use this function to receive information about a ziplist entry.
675 * Note that this is not how the data is actually encoded, is just what we
676 * get filled by a function in order to operate more easily. */
677@@ -709,7 +720,8 @@ unsigned char *ziplistNew(void) {
678 }
679
680 /* Resize the ziplist. */
681-unsigned char *ziplistResize(unsigned char *zl, unsigned int len) {
682+unsigned char *ziplistResize(unsigned char *zl, size_t len) {
683+ assert(len < UINT32_MAX);
684 zl = zrealloc(zl,len);
685 ZIPLIST_BYTES(zl) = intrev32ifbe(len);
686 zl[len-1] = ZIP_END;
687@@ -1070,6 +1082,9 @@ unsigned char *ziplistMerge(unsigned char **first, unsigned char **second) {
688 /* Combined zl length should be limited within UINT16_MAX */
689 zllength = zllength < UINT16_MAX ? zllength : UINT16_MAX;
690
691+ /* larger values can't be stored into ZIPLIST_BYTES */
692+ assert(zlbytes < UINT32_MAX);
693+
694 /* Save offset positions before we start ripping memory apart. */
695 size_t first_offset = intrev32ifbe(ZIPLIST_TAIL_OFFSET(*first));
696 size_t second_offset = intrev32ifbe(ZIPLIST_TAIL_OFFSET(*second));
697diff --git a/src/ziplist.h b/src/ziplist.h
698index 9e7997ad8..569e1259d 100644
699--- a/src/ziplist.h
700+++ b/src/ziplist.h
701@@ -65,6 +65,7 @@ int ziplistValidateIntegrity(unsigned char *zl, size_t size, int deep,
702 void ziplistRandomPair(unsigned char *zl, unsigned long total_count, ziplistEntry *key, ziplistEntry *val);
703 void ziplistRandomPairs(unsigned char *zl, unsigned int count, ziplistEntry *keys, ziplistEntry *vals);
704 unsigned int ziplistRandomPairsUnique(unsigned char *zl, unsigned int count, ziplistEntry *keys, ziplistEntry *vals);
705+int ziplistSafeToAdd(unsigned char* zl, size_t add);
706
707 #ifdef REDIS_TEST
708 int ziplistTest(int argc, char *argv[], int accurate);
709diff --git a/tests/unit/violations.tcl b/tests/unit/violations.tcl
710new file mode 100644
711index 000000000..1d3140c52
712--- /dev/null
713+++ b/tests/unit/violations.tcl
714@@ -0,0 +1,156 @@
715+# These tests consume massive amounts of memory, and are not
716+# suitable to be executed as part of the normal test suite
717+set ::str500 [string repeat x 500000000] ;# 500mb
718+
719+# Utility function to write big argument into redis client connection
720+proc write_big_bulk {size} {
721+ r write "\$$size\r\n"
722+ while {$size >= 500000000} {
723+ r write $::str500
724+ incr size -500000000
725+ }
726+ if {$size > 0} {
727+ r write [string repeat x $size]
728+ }
729+ r write "\r\n"
730+}
731+
732+# One XADD with one huge 5GB field
733+# Expected to fail resulting in an empty stream
734+start_server [list overrides [list save ""] ] {
735+ test {XADD one huge field} {
736+ r config set proto-max-bulk-len 10000000000 ;#10gb
737+ r config set client-query-buffer-limit 10000000000 ;#10gb
738+ r write "*5\r\n\$4\r\nXADD\r\n\$2\r\nS1\r\n\$1\r\n*\r\n"
739+ r write "\$1\r\nA\r\n"
740+ write_big_bulk 5000000000 ;#5gb
741+ r flush
742+ catch {r read} err
743+ assert_match {*too large*} $err
744+ r xlen S1
745+ } {0}
746+}
747+
748+# One XADD with one huge (exactly nearly) 4GB field
749+# This uncovers the overflow in lpEncodeGetType
750+# Expected to fail resulting in an empty stream
751+start_server [list overrides [list save ""] ] {
752+ test {XADD one huge field - 1} {
753+ r config set proto-max-bulk-len 10000000000 ;#10gb
754+ r config set client-query-buffer-limit 10000000000 ;#10gb
755+ r write "*5\r\n\$4\r\nXADD\r\n\$2\r\nS1\r\n\$1\r\n*\r\n"
756+ r write "\$1\r\nA\r\n"
757+ write_big_bulk 4294967295 ;#4gb-1
758+ r flush
759+ catch {r read} err
760+ assert_match {*too large*} $err
761+ r xlen S1
762+ } {0}
763+}
764+
765+# Gradually add big stream fields using repeated XADD calls
766+start_server [list overrides [list save ""] ] {
767+ test {several XADD big fields} {
768+ r config set stream-node-max-bytes 0
769+ for {set j 0} {$j<10} {incr j} {
770+ r xadd stream * 1 $::str500 2 $::str500
771+ }
772+ r ping
773+ r xlen stream
774+ } {10}
775+}
776+
777+# Add over 4GB to a single stream listpack (one XADD command)
778+# Expected to fail resulting in an empty stream
779+start_server [list overrides [list save ""] ] {
780+ test {single XADD big fields} {
781+ r write "*23\r\n\$4\r\nXADD\r\n\$1\r\nS\r\n\$1\r\n*\r\n"
782+ for {set j 0} {$j<10} {incr j} {
783+ r write "\$1\r\n$j\r\n"
784+ write_big_bulk 500000000 ;#500mb
785+ }
786+ r flush
787+ catch {r read} err
788+ assert_match {*too large*} $err
789+ r xlen S
790+ } {0}
791+}
792+
793+# Gradually add big hash fields using repeated HSET calls
794+# This reproduces the overflow in the call to ziplistResize
795+# Object will be converted to hashtable encoding
796+start_server [list overrides [list save ""] ] {
797+ r config set hash-max-ziplist-value 1000000000 ;#1gb
798+ test {hash with many big fields} {
799+ for {set j 0} {$j<10} {incr j} {
800+ r hset h $j $::str500
801+ }
802+ r object encoding h
803+ } {hashtable}
804+}
805+
806+# Add over 4GB to a single hash field (one HSET command)
807+# Object will be converted to hashtable encoding
808+start_server [list overrides [list save ""] ] {
809+ test {hash with one huge field} {
810+ catch {r config set hash-max-ziplist-value 10000000000} ;#10gb
811+ r config set proto-max-bulk-len 10000000000 ;#10gb
812+ r config set client-query-buffer-limit 10000000000 ;#10gb
813+ r write "*4\r\n\$4\r\nHSET\r\n\$2\r\nH1\r\n"
814+ r write "\$1\r\nA\r\n"
815+ write_big_bulk 5000000000 ;#5gb
816+ r flush
817+ r read
818+ r object encoding H1
819+ } {hashtable}
820+}
821+
822+# Add over 4GB to a single list member (one LPUSH command)
823+# Currently unsupported, and expected to fail rather than being truncated
824+# Expected to fail resulting in a non-existing list
825+start_server [list overrides [list save ""] ] {
826+ test {list with one huge field} {
827+ r config set proto-max-bulk-len 10000000000 ;#10gb
828+ r config set client-query-buffer-limit 10000000000 ;#10gb
829+ r write "*3\r\n\$5\r\nLPUSH\r\n\$2\r\nL1\r\n"
830+ write_big_bulk 5000000000 ;#5gb
831+ r flush
832+ catch {r read} err
833+ assert_match {*too large*} $err
834+ r exists L1
835+ } {0}
836+}
837+
838+# SORT which attempts to store an element larger than 4GB into a list.
839+# Currently unsupported and results in an assertion instead of truncation
840+start_server [list overrides [list save ""] ] {
841+ test {SORT adds huge field to list} {
842+ r config set proto-max-bulk-len 10000000000 ;#10gb
843+ r config set client-query-buffer-limit 10000000000 ;#10gb
844+ r write "*3\r\n\$3\r\nSET\r\n\$2\r\nS1\r\n"
845+ write_big_bulk 5000000000 ;#5gb
846+ r flush
847+ r read
848+ assert_equal [r strlen S1] 5000000000
849+ r set S2 asdf
850+ r sadd myset 1 2
851+ r mset D1 1 D2 2
852+ catch {r sort myset by D* get S* store mylist}
853+ assert_equal [count_log_message 0 "crashed by signal"] 0
854+ assert_equal [count_log_message 0 "ASSERTION FAILED"] 1
855+ }
856+}
857+
858+# SORT which stores an integer encoded element into a list.
859+# Just for coverage, no news here.
860+start_server [list overrides [list save ""] ] {
861+ test {SORT adds integer field to list} {
862+ r set S1 asdf
863+ r set S2 123 ;# integer encoded
864+ assert_encoding "int" S2
865+ r sadd myset 1 2
866+ r mset D1 1 D2 2
867+ r sort myset by D* get S* store mylist
868+ r llen mylist
869+ } {2}
870+}
871--
8722.17.1
873
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32675.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32675.patch
deleted file mode 100644
index ab691612a9..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-32675.patch
+++ /dev/null
@@ -1,129 +0,0 @@
1From a71a65e9ed75b347c33bc882b38f4f1006fcba39 Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Wed, 9 Jun 2021 17:31:39 +0300
4Subject: [PATCH] Prevent unauthenticated client from easily consuming lots of
5 memory (CVE-2021-32675)
6
7This change sets a low limit for multibulk and bulk length in the
8protocol for unauthenticated connections, so that they can't easily
9cause redis to allocate massive amounts of memory by sending just a few
10characters on the network.
11The new limits are 10 arguments of 16kb each (instead of 1m of 512mb)
12
13CVE: CVE-2021-32675
14Upstream-Status: Backport[https://github.com/redis/redis/commit/5674b0057ff2903d43eaff802017eddf37c360f8]
15
16Signed-off-by: Changqing Li <changqing.li@windriver.com>
17---
18 src/networking.c | 17 +++++++++++++++++
19 src/server.c | 11 +++--------
20 src/server.h | 1 +
21 tests/unit/auth.tcl | 16 ++++++++++++++++
22 4 files changed, 37 insertions(+), 8 deletions(-)
23
24diff --git a/src/networking.c b/src/networking.c
25index 2355a37..8e891c6 100644
26--- a/src/networking.c
27+++ b/src/networking.c
28@@ -107,6 +107,15 @@ static void clientSetDefaultAuth(client *c) {
29 !(c->user->flags & USER_FLAG_DISABLED);
30 }
31
32+int authRequired(client *c) {
33+ /* Check if the user is authenticated. This check is skipped in case
34+ * the default user is flagged as "nopass" and is active. */
35+ int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
36+ (DefaultUser->flags & USER_FLAG_DISABLED)) &&
37+ !c->authenticated;
38+ return auth_required;
39+}
40+
41 client *createClient(connection *conn) {
42 client *c = zmalloc(sizeof(client));
43
44@@ -1855,6 +1864,10 @@ int processMultibulkBuffer(client *c) {
45 addReplyError(c,"Protocol error: invalid multibulk length");
46 setProtocolError("invalid mbulk count",c);
47 return C_ERR;
48+ } else if (ll > 10 && authRequired(c)) {
49+ addReplyError(c, "Protocol error: unauthenticated multibulk length");
50+ setProtocolError("unauth mbulk count", c);
51+ return C_ERR;
52 }
53
54 c->qb_pos = (newline-c->querybuf)+2;
55@@ -1902,6 +1915,10 @@ int processMultibulkBuffer(client *c) {
56 addReplyError(c,"Protocol error: invalid bulk length");
57 setProtocolError("invalid bulk length",c);
58 return C_ERR;
59+ } else if (ll > 16384 && authRequired(c)) {
60+ addReplyError(c, "Protocol error: unauthenticated bulk length");
61+ setProtocolError("unauth bulk length", c);
62+ return C_ERR;
63 }
64
65 c->qb_pos = newline-c->querybuf+2;
66diff --git a/src/server.c b/src/server.c
67index 9932606..f65ad22 100644
68--- a/src/server.c
69+++ b/src/server.c
70@@ -3996,14 +3996,9 @@ int processCommand(client *c) {
71 int is_may_replicate_command = (c->cmd->flags & (CMD_WRITE | CMD_MAY_REPLICATE)) ||
72 (c->cmd->proc == execCommand && (c->mstate.cmd_flags & (CMD_WRITE | CMD_MAY_REPLICATE)));
73
74- /* Check if the user is authenticated. This check is skipped in case
75- * the default user is flagged as "nopass" and is active. */
76- int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
77- (DefaultUser->flags & USER_FLAG_DISABLED)) &&
78- !c->authenticated;
79- if (auth_required) {
80- /* AUTH and HELLO and no auth modules are valid even in
81- * non-authenticated state. */
82+ if (authRequired(c)) {
83+ /* AUTH and HELLO and no auth commands are valid even in
84+ * non-authenticated state. */
85 if (!(c->cmd->flags & CMD_NO_AUTH)) {
86 rejectCommand(c,shared.noautherr);
87 return C_OK;
88diff --git a/src/server.h b/src/server.h
89index e256ce0..a3dfe60 100644
90--- a/src/server.h
91+++ b/src/server.h
92@@ -1894,6 +1894,7 @@ void protectClient(client *c);
93 void unprotectClient(client *c);
94 void initThreadedIO(void);
95 client *lookupClientByID(uint64_t id);
96+int authRequired(client *c);
97
98 #ifdef __GNUC__
99 void addReplyErrorFormat(client *c, const char *fmt, ...)
100diff --git a/tests/unit/auth.tcl b/tests/unit/auth.tcl
101index b63cf01..5997707 100644
102--- a/tests/unit/auth.tcl
103+++ b/tests/unit/auth.tcl
104@@ -24,6 +24,22 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
105 r set foo 100
106 r incr foo
107 } {101}
108+
109+ test {For unauthenticated clients multibulk and bulk length are limited} {
110+ set rr [redis [srv "host"] [srv "port"] 0 $::tls]
111+ $rr write "*100\r\n"
112+ $rr flush
113+ catch {[$rr read]} e
114+ assert_match {*unauthenticated multibulk length*} $e
115+ $rr close
116+
117+ set rr [redis [srv "host"] [srv "port"] 0 $::tls]
118+ $rr write "*1\r\n\$100000000\r\n"
119+ $rr flush
120+ catch {[$rr read]} e
121+ assert_match {*unauthenticated bulk length*} $e
122+ $rr close
123+ }
124 }
125
126 start_server {tags {"auth_binary_password"}} {
127--
1282.17.1
129
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32687.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32687.patch
deleted file mode 100644
index fe04e67f30..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-32687.patch
+++ /dev/null
@@ -1,67 +0,0 @@
1From a40ee258accdaf56c23950a6371307ca1aa69f06 Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Sun, 26 Sep 2021 15:42:17 +0300
4Subject: [PATCH] Fix Integer overflow issue with intsets (CVE-2021-32687)
5
6The vulnerability involves changing the default set-max-intset-entries
7configuration parameter to a very large value and constructing specially
8crafted commands to manipulate sets
9
10CVE: CVE-2021-32687
11Upstream-Status: Backport[https://github.com/redis/redis/commit/a30d367a71b7017581cf1ca104242a3c644dec0f]
12
13Signed-off-by: Changqing Li <changqing.li@windriver.com>
14---
15 src/intset.c | 3 ++-
16 src/rdb.c | 4 +++-
17 src/t_set.c | 5 ++++-
18 3 files changed, 9 insertions(+), 3 deletions(-)
19
20diff --git a/src/intset.c b/src/intset.c
21index 9ba1389..e366851 100644
22--- a/src/intset.c
23+++ b/src/intset.c
24@@ -104,7 +104,8 @@ intset *intsetNew(void) {
25
26 /* Resize the intset */
27 static intset *intsetResize(intset *is, uint32_t len) {
28- uint32_t size = len*intrev32ifbe(is->encoding);
29+ uint64_t size = (uint64_t)len*intrev32ifbe(is->encoding);
30+ assert(size <= SIZE_MAX - sizeof(intset));
31 is = zrealloc(is,sizeof(intset)+size);
32 return is;
33 }
34diff --git a/src/rdb.c b/src/rdb.c
35index 6f2f516..37b1e0b 100644
36--- a/src/rdb.c
37+++ b/src/rdb.c
38@@ -1562,7 +1562,9 @@ robj *rdbLoadObject(int rdbtype, rio *rdb, sds key) {
39 if ((len = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL;
40
41 /* Use a regular set when there are too many entries. */
42- if (len > server.set_max_intset_entries) {
43+ size_t max_entries = server.set_max_intset_entries;
44+ if (max_entries >= 1<<30) max_entries = 1<<30;
45+ if (len > max_entries) {
46 o = createSetObject();
47 /* It's faster to expand the dict to the right size asap in order
48 * to avoid rehashing */
49diff --git a/src/t_set.c b/src/t_set.c
50index b655b71..d50a05a 100644
51--- a/src/t_set.c
52+++ b/src/t_set.c
53@@ -66,7 +66,10 @@ int setTypeAdd(robj *subject, sds value) {
54 if (success) {
55 /* Convert to regular set when the intset contains
56 * too many entries. */
57- if (intsetLen(subject->ptr) > server.set_max_intset_entries)
58+ size_t max_entries = server.set_max_intset_entries;
59+ /* limit to 1G entries due to intset internals. */
60+ if (max_entries >= 1<<30) max_entries = 1<<30;
61+ if (intsetLen(subject->ptr) > max_entries)
62 setTypeConvert(subject,OBJ_ENCODING_HT);
63 return 1;
64 }
65--
662.17.1
67
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch
deleted file mode 100644
index 14992b789a..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-32761.patch
+++ /dev/null
@@ -1,257 +0,0 @@
1From 835d15b5360e277e6f95529c4d8685946a977ddd Mon Sep 17 00:00:00 2001
2From: Huang Zhw <huang_zhw@126.com>
3Date: Wed, 21 Jul 2021 21:25:19 +0800
4Subject: [PATCH 1/1] On 32 bit platform, the bit position of
5 GETBIT/SETBIT/BITFIELD/BITCOUNT,BITPOS may overflow (see CVE-2021-32761)
6 (#9191)
7
8GETBIT, SETBIT may access wrong address because of wrap.
9BITCOUNT and BITPOS may return wrapped results.
10BITFIELD may access the wrong address but also allocate insufficient memory and segfault (see CVE-2021-32761).
11
12This commit uses `uint64_t` or `long long` instead of `size_t`.
13related https://github.com/redis/redis/pull/8096
14
15At 32bit platform:
16> setbit bit 4294967295 1
17(integer) 0
18> config set proto-max-bulk-len 536870913
19OK
20> append bit "\xFF"
21(integer) 536870913
22> getbit bit 4294967296
23(integer) 0
24
25When the bit index is larger than 4294967295, size_t can't hold bit index. In the past, `proto-max-bulk-len` is limit to 536870912, so there is no problem.
26
27After this commit, bit position is stored in `uint64_t` or `long long`. So when `proto-max-bulk-len > 536870912`, 32bit platforms can still be correct.
28
29For 64bit platform, this problem still exists. The major reason is bit pos 8 times of byte pos. When proto-max-bulk-len is very larger, bit pos may overflow.
30But at 64bit platform, we don't have so long string. So this bug may never happen.
31
32Additionally this commit add a test cost `512MB` memory which is tag as `large-memory`. Make freebsd ci and valgrind ci ignore this test.
33
34(cherry picked from commit 71d452876ebf8456afaadd6b3c27988abadd1148)d
35---
36
37CVE: CVE-2021-32761
38
39Upstream-Status: Backport [835d15b5360e277e6f95529c4d8685946a977ddd]
40 https://github.com/redis/redis.git
41
42Signed-off-by: Joe Slater <joe.slater@windriver.com>
43
44---
45 .github/workflows/daily.yml | 6 +++---
46 src/bitops.c | 32 ++++++++++++++++----------------
47 src/server.h | 2 +-
48 tests/unit/bitops.tcl | 28 ++++++++++++++++++++++++++++
49 4 files changed, 48 insertions(+), 20 deletions(-)
50
51diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml
52index 9e4630e29..432971a9d 100644
53--- a/.github/workflows/daily.yml
54+++ b/.github/workflows/daily.yml
55@@ -151,7 +151,7 @@ jobs:
56 run: |
57 sudo apt-get update
58 sudo apt-get install tcl8.6 valgrind -y
59- ./runtest --valgrind --verbose --clients 1 --dump-logs
60+ ./runtest --valgrind --verbose --clients 1 --tags -large-memory --dump-logs
61 - name: module api test
62 run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
63 - name: unittest
64@@ -171,7 +171,7 @@ jobs:
65 run: |
66 sudo apt-get update
67 sudo apt-get install tcl8.6 valgrind -y
68- ./runtest --valgrind --verbose --clients 1 --dump-logs
69+ ./runtest --valgrind --verbose --clients 1 --tags -large-memory --dump-logs
70 - name: module api test
71 run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
72
73@@ -260,7 +260,7 @@ jobs:
74 prepare: pkg install -y bash gmake lang/tcl86
75 run: >
76 gmake &&
77- ./runtest --accurate --verbose --no-latency --dump-logs &&
78+ ./runtest --accurate --verbose --no-latency --tags -large-memory --dump-logs &&
79 MAKE=gmake ./runtest-moduleapi --verbose &&
80 ./runtest-sentinel &&
81 ./runtest-cluster
82diff --git a/src/bitops.c b/src/bitops.c
83index afd79ad88..f1c563a41 100644
84--- a/src/bitops.c
85+++ b/src/bitops.c
86@@ -37,8 +37,8 @@
87 /* Count number of bits set in the binary array pointed by 's' and long
88 * 'count' bytes. The implementation of this function is required to
89 * work with an input string length up to 512 MB or more (server.proto_max_bulk_len) */
90-size_t redisPopcount(void *s, long count) {
91- size_t bits = 0;
92+long long redisPopcount(void *s, long count) {
93+ long long bits = 0;
94 unsigned char *p = s;
95 uint32_t *p4;
96 static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
97@@ -98,11 +98,11 @@ size_t redisPopcount(void *s, long count) {
98 * no zero bit is found, it returns count*8 assuming the string is zero
99 * padded on the right. However if 'bit' is 1 it is possible that there is
100 * not a single set bit in the bitmap. In this special case -1 is returned. */
101-long redisBitpos(void *s, unsigned long count, int bit) {
102+long long redisBitpos(void *s, unsigned long count, int bit) {
103 unsigned long *l;
104 unsigned char *c;
105 unsigned long skipval, word = 0, one;
106- long pos = 0; /* Position of bit, to return to the caller. */
107+ long long pos = 0; /* Position of bit, to return to the caller. */
108 unsigned long j;
109 int found;
110
111@@ -410,7 +410,7 @@ void printBits(unsigned char *p, unsigned long count) {
112 * If the 'hash' argument is true, and 'bits is positive, then the command
113 * will also parse bit offsets prefixed by "#". In such a case the offset
114 * is multiplied by 'bits'. This is useful for the BITFIELD command. */
115-int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int bits) {
116+int getBitOffsetFromArgument(client *c, robj *o, uint64_t *offset, int hash, int bits) {
117 long long loffset;
118 char *err = "bit offset is not an integer or out of range";
119 char *p = o->ptr;
120@@ -435,7 +435,7 @@ int getBitOffsetFromArgument(client *c, robj *o, size_t *offset, int hash, int b
121 return C_ERR;
122 }
123
124- *offset = (size_t)loffset;
125+ *offset = loffset;
126 return C_OK;
127 }
128
129@@ -477,7 +477,7 @@ int getBitfieldTypeFromArgument(client *c, robj *o, int *sign, int *bits) {
130 * so that the 'maxbit' bit can be addressed. The object is finally
131 * returned. Otherwise if the key holds a wrong type NULL is returned and
132 * an error is sent to the client. */
133-robj *lookupStringForBitCommand(client *c, size_t maxbit) {
134+robj *lookupStringForBitCommand(client *c, uint64_t maxbit) {
135 size_t byte = maxbit >> 3;
136 robj *o = lookupKeyWrite(c->db,c->argv[1]);
137 if (checkType(c,o,OBJ_STRING)) return NULL;
138@@ -527,7 +527,7 @@ unsigned char *getObjectReadOnlyString(robj *o, long *len, char *llbuf) {
139 void setbitCommand(client *c) {
140 robj *o;
141 char *err = "bit is not an integer or out of range";
142- size_t bitoffset;
143+ uint64_t bitoffset;
144 ssize_t byte, bit;
145 int byteval, bitval;
146 long on;
147@@ -566,7 +566,7 @@ void setbitCommand(client *c) {
148 void getbitCommand(client *c) {
149 robj *o;
150 char llbuf[32];
151- size_t bitoffset;
152+ uint64_t bitoffset;
153 size_t byte, bit;
154 size_t bitval = 0;
155
156@@ -888,7 +888,7 @@ void bitposCommand(client *c) {
157 addReplyLongLong(c, -1);
158 } else {
159 long bytes = end-start+1;
160- long pos = redisBitpos(p+start,bytes,bit);
161+ long long pos = redisBitpos(p+start,bytes,bit);
162
163 /* If we are looking for clear bits, and the user specified an exact
164 * range with start-end, we can't consider the right of the range as
165@@ -897,11 +897,11 @@ void bitposCommand(client *c) {
166 * So if redisBitpos() returns the first bit outside the range,
167 * we return -1 to the caller, to mean, in the specified range there
168 * is not a single "0" bit. */
169- if (end_given && bit == 0 && pos == bytes*8) {
170+ if (end_given && bit == 0 && pos == (long long)bytes<<3) {
171 addReplyLongLong(c,-1);
172 return;
173 }
174- if (pos != -1) pos += start*8; /* Adjust for the bytes we skipped. */
175+ if (pos != -1) pos += (long long)start<<3; /* Adjust for the bytes we skipped. */
176 addReplyLongLong(c,pos);
177 }
178 }
179@@ -933,12 +933,12 @@ struct bitfieldOp {
180 * GET subcommand is allowed, other subcommands will return an error. */
181 void bitfieldGeneric(client *c, int flags) {
182 robj *o;
183- size_t bitoffset;
184+ uint64_t bitoffset;
185 int j, numops = 0, changes = 0;
186 struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */
187 int owtype = BFOVERFLOW_WRAP; /* Overflow type. */
188 int readonly = 1;
189- size_t highest_write_offset = 0;
190+ uint64_t highest_write_offset = 0;
191
192 for (j = 2; j < c->argc; j++) {
193 int remargs = c->argc-j-1; /* Remaining args other than current. */
194@@ -1128,9 +1128,9 @@ void bitfieldGeneric(client *c, int flags) {
195 * object boundaries. */
196 memset(buf,0,9);
197 int i;
198- size_t byte = thisop->offset >> 3;
199+ uint64_t byte = thisop->offset >> 3;
200 for (i = 0; i < 9; i++) {
201- if (src == NULL || i+byte >= (size_t)strlen) break;
202+ if (src == NULL || i+byte >= (uint64_t)strlen) break;
203 buf[i] = src[i+byte];
204 }
205
206diff --git a/src/server.h b/src/server.h
207index 67541fe60..caf9df31c 100644
208--- a/src/server.h
209+++ b/src/server.h
210@@ -1795,7 +1795,7 @@ void getRandomHexChars(char *p, size_t len);
211 void getRandomBytes(unsigned char *p, size_t len);
212 uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l);
213 void exitFromChild(int retcode);
214-size_t redisPopcount(void *s, long count);
215+long long redisPopcount(void *s, long count);
216 int redisSetProcTitle(char *title);
217 int validateProcTitleTemplate(const char *template);
218 int redisCommunicateSystemd(const char *sd_notify_msg);
219diff --git a/tests/unit/bitops.tcl b/tests/unit/bitops.tcl
220index 926f38295..534832974 100644
221--- a/tests/unit/bitops.tcl
222+++ b/tests/unit/bitops.tcl
223@@ -349,3 +349,31 @@ start_server {tags {"bitops"}} {
224 }
225 }
226 }
227+
228+start_server {tags {"bitops large-memory"}} {
229+ test "BIT pos larger than UINT_MAX" {
230+ set bytes [expr (1 << 29) + 1]
231+ set bitpos [expr (1 << 32)]
232+ set oldval [lindex [r config get proto-max-bulk-len] 1]
233+ r config set proto-max-bulk-len $bytes
234+ r setbit mykey $bitpos 1
235+ assert_equal $bytes [r strlen mykey]
236+ assert_equal 1 [r getbit mykey $bitpos]
237+ assert_equal [list 128 128 -1] [r bitfield mykey get u8 $bitpos set u8 $bitpos 255 get i8 $bitpos]
238+ assert_equal $bitpos [r bitpos mykey 1]
239+ assert_equal $bitpos [r bitpos mykey 1 [expr $bytes - 1]]
240+ if {$::accurate} {
241+ # set all bits to 1
242+ set mega [expr (1 << 23)]
243+ set part [string repeat "\xFF" $mega]
244+ for {set i 0} {$i < 64} {incr i} {
245+ r setrange mykey [expr $i * $mega] $part
246+ }
247+ r setrange mykey [expr $bytes - 1] "\xFF"
248+ assert_equal [expr $bitpos + 8] [r bitcount mykey]
249+ assert_equal -1 [r bitpos mykey 0 0 [expr $bytes - 1]]
250+ }
251+ r config set proto-max-bulk-len $oldval
252+ r del mykey
253+ } {1}
254+}
255--
2562.24.1
257
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-32762.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-32762.patch
deleted file mode 100644
index ec6e2fbd5b..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-32762.patch
+++ /dev/null
@@ -1,68 +0,0 @@
1From 4b1de5438ad9ef2236c379f2f78feb9f1fd9796e Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Mon, 4 Oct 2021 12:10:17 +0300
4Subject: [PATCH] Fix redis-cli / redis-sential overflow on some platforms
5 (CVE-2021-32762) (#9587)
6
7The redis-cli command line tool and redis-sentinel service may be vulnerable
8to integer overflow when parsing specially crafted large multi-bulk network
9replies. This is a result of a vulnerability in the underlying hiredis
10library which does not perform an overflow check before calling the calloc()
11heap allocation function.
12
13This issue only impacts systems with heap allocators that do not perform their
14own overflow checks. Most modern systems do and are therefore not likely to
15be affected. Furthermore, by default redis-sentinel uses the jemalloc allocator
16which is also not vulnerable.
17
18Co-authored-by: Yossi Gottlieb <yossigo@gmail.com>
19
20CVE: CVE-2021-32762
21Upstream-Status: Backport[https://github.com/redis/redis/commit/0215324a66af949be39b34be2d55143232c1cb71]
22
23Signed-off-by: Changqing Li <changqing.li@windriver.com>
24---
25 deps/hiredis/hiredis.c | 1 +
26 deps/hiredis/test.c | 14 ++++++++++++++
27 2 files changed, 15 insertions(+)
28
29diff --git a/deps/hiredis/hiredis.c b/deps/hiredis/hiredis.c
30index 51f22a6..990f619 100644
31--- a/deps/hiredis/hiredis.c
32+++ b/deps/hiredis/hiredis.c
33@@ -174,6 +174,7 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) {
34 return NULL;
35
36 if (elements > 0) {
37+ if (SIZE_MAX / sizeof(redisReply*) < elements) return NULL; /* Don't overflow */
38 r->element = hi_calloc(elements,sizeof(redisReply*));
39 if (r->element == NULL) {
40 freeReplyObject(r);
41diff --git a/deps/hiredis/test.c b/deps/hiredis/test.c
42index 8295367..bdff74e 100644
43--- a/deps/hiredis/test.c
44+++ b/deps/hiredis/test.c
45@@ -498,6 +498,20 @@ static void test_reply_reader(void) {
46 freeReplyObject(reply);
47 redisReaderFree(reader);
48
49+ test("Multi-bulk never overflows regardless of maxelements: ");
50+ size_t bad_mbulk_len = (SIZE_MAX / sizeof(void *)) + 3;
51+ char bad_mbulk_reply[100];
52+ snprintf(bad_mbulk_reply, sizeof(bad_mbulk_reply), "*%llu\r\n+asdf\r\n",
53+ (unsigned long long) bad_mbulk_len);
54+
55+ reader = redisReaderCreate();
56+ reader->maxelements = 0; /* Don't rely on default limit */
57+ redisReaderFeed(reader, bad_mbulk_reply, strlen(bad_mbulk_reply));
58+ ret = redisReaderGetReply(reader,&reply);
59+ test_cond(ret == REDIS_ERR && strcasecmp(reader->errstr, "Out of memory") == 0);
60+ freeReplyObject(reply);
61+ redisReaderFree(reader);
62+
63 #if LLONG_MAX > SIZE_MAX
64 test("Set error when array > SIZE_MAX: ");
65 reader = redisReaderCreate();
66--
672.17.1
68
diff --git a/meta-oe/recipes-extended/redis/redis/CVE-2021-41099.patch b/meta-oe/recipes-extended/redis/redis/CVE-2021-41099.patch
deleted file mode 100644
index ce0e112aeb..0000000000
--- a/meta-oe/recipes-extended/redis/redis/CVE-2021-41099.patch
+++ /dev/null
@@ -1,47 +0,0 @@
1From fd25ce2108994b7781269143bdfb3403faa2f1d1 Mon Sep 17 00:00:00 2001
2From: YiyuanGUO <yguoaz@gmail.com>
3Date: Wed, 29 Sep 2021 10:20:35 +0300
4Subject: [PATCH] Fix integer overflow in _sdsMakeRoomFor (CVE-2021-41099)
5
6CVE: CVE-2021-41099
7Upstream-Status: Backport[https://github.com/redis/redis/commit/c6ad876774f3cc11e32681ea02a2eead00f2c521]
8
9Signed-off-by: Changqing Li <changqing.li@windriver.com>
10---
11 src/sds.c | 6 +++---
12 1 file changed, 3 insertions(+), 3 deletions(-)
13
14diff --git a/src/sds.c b/src/sds.c
15index 2ec3aa7..5eadae5 100644
16--- a/src/sds.c
17+++ b/src/sds.c
18@@ -233,7 +233,7 @@ void sdsclear(sds s) {
19 sds sdsMakeRoomFor(sds s, size_t addlen) {
20 void *sh, *newsh;
21 size_t avail = sdsavail(s);
22- size_t len, newlen;
23+ size_t len, newlen, reqlen;
24 char type, oldtype = s[-1] & SDS_TYPE_MASK;
25 int hdrlen;
26 size_t usable;
27@@ -243,7 +243,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
28
29 len = sdslen(s);
30 sh = (char*)s-sdsHdrSize(oldtype);
31- newlen = (len+addlen);
32+ reqlen = newlen = (len+addlen);
33 assert(newlen > len); /* Catch size_t overflow */
34 if (newlen < SDS_MAX_PREALLOC)
35 newlen *= 2;
36@@ -258,7 +258,7 @@ sds sdsMakeRoomFor(sds s, size_t addlen) {
37 if (type == SDS_TYPE_5) type = SDS_TYPE_8;
38
39 hdrlen = sdsHdrSize(type);
40- assert(hdrlen + newlen + 1 > len); /* Catch size_t overflow */
41+ assert(hdrlen + newlen + 1 > reqlen); /* Catch size_t overflow */
42 if (oldtype==type) {
43 newsh = s_realloc_usable(sh, hdrlen+newlen+1, &usable);
44 if (newsh == NULL) return NULL;
45--
462.17.1
47
diff --git a/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29477.patch b/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29477.patch
deleted file mode 100644
index a5e5a1ba55..0000000000
--- a/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29477.patch
+++ /dev/null
@@ -1,35 +0,0 @@
1From f0c5f920d0f88bd8aa376a2c05af4902789d1ef9 Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Mon, 3 May 2021 08:32:31 +0300
4Subject: [PATCH] Fix integer overflow in STRALGO LCS (CVE-2021-29477)
5
6An integer overflow bug in Redis version 6.0 or newer could be exploited using
7the STRALGO LCS command to corrupt the heap and potentially result with remote
8code execution.
9
10CVE: CVE-2021-29477
11Upstream-Status: Backport
12[https://github.com/redis/redis/commit/f0c5f920d0f88bd8aa376a2c05af4902789d1ef9]
13
14Signed-off-by: Tony Tascioglu <tony.tascioglu@windriver.com>
15
16---
17 src/t_string.c | 2 +-
18 1 file changed, 1 insertion(+), 1 deletion(-)
19
20diff --git a/src/t_string.c b/src/t_string.c
21index 9228c5ed0..db6f7042e 100644
22--- a/src/t_string.c
23+++ b/src/t_string.c
24@@ -805,7 +805,7 @@ void stralgoLCS(client *c) {
25 /* Setup an uint32_t array to store at LCS[i,j] the length of the
26 * LCS A0..i-1, B0..j-1. Note that we have a linear array here, so
27 * we index it as LCS[j+(blen+1)*j] */
28- uint32_t *lcs = zmalloc((alen+1)*(blen+1)*sizeof(uint32_t));
29+ uint32_t *lcs = zmalloc((size_t)(alen+1)*(blen+1)*sizeof(uint32_t));
30 #define LCS(A,B) lcs[(B)+((A)*(blen+1))]
31
32 /* Start building the LCS table. */
33--
342.32.0
35
diff --git a/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29478.patch b/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29478.patch
deleted file mode 100644
index ebbf6e1b94..0000000000
--- a/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-29478.patch
+++ /dev/null
@@ -1,42 +0,0 @@
1From 29900d4e6bccdf3691bedf0ea9a5d84863fa3592 Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Mon, 3 May 2021 08:27:22 +0300
4Subject: [PATCH] Fix integer overflow in intset (CVE-2021-29478)
5
6An integer overflow bug in Redis 6.2 could be exploited to corrupt the heap and
7potentially result with remote code execution.
8
9The vulnerability involves changing the default set-max-intset-entries
10configuration value, creating a large set key that consists of integer values
11and using the COPY command to duplicate it.
12
13The integer overflow bug exists in all versions of Redis starting with 2.6,
14where it could result with a corrupted RDB or DUMP payload, but not exploited
15through COPY (which did not exist before 6.2).
16
17CVE: CVE-2021-29478
18Upstream-Status: Backport
19[https://github.com/redis/redis/commit/29900d4e6bccdf3691bedf0ea9a5d84863fa3592]
20
21Signed-off-by: Tony Tascioglu <tony.tascioglu@windriver.com>
22
23---
24 src/intset.c | 2 +-
25 1 file changed, 1 insertion(+), 1 deletion(-)
26
27diff --git a/src/intset.c b/src/intset.c
28index 1a64ecae8..9ba13898d 100644
29--- a/src/intset.c
30+++ b/src/intset.c
31@@ -281,7 +281,7 @@ uint32_t intsetLen(const intset *is) {
32
33 /* Return intset blob size in bytes. */
34 size_t intsetBlobLen(intset *is) {
35- return sizeof(intset)+intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
36+ return sizeof(intset)+(size_t)intrev32ifbe(is->length)*intrev32ifbe(is->encoding);
37 }
38
39 /* Validate the integrity of the data structure.
40--
412.32.0
42
diff --git a/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-32625.patch b/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-32625.patch
deleted file mode 100644
index 6311a5db10..0000000000
--- a/meta-oe/recipes-extended/redis/redis/fix-CVE-2021-32625.patch
+++ /dev/null
@@ -1,61 +0,0 @@
1From e9a1438ac4c52aa68dfa2a8324b6419356842116 Mon Sep 17 00:00:00 2001
2From: Oran Agra <oran@redislabs.com>
3Date: Tue, 1 Jun 2021 09:12:45 +0300
4Subject: [PATCH] Fix integer overflow in STRALGO LCS (CVE-2021-32625) (#9011)
5
6An integer overflow bug in Redis version 6.0 or newer can be exploited using the
7STRALGO LCS command to corrupt the heap and potentially result with remote code
8execution. This is a result of an incomplete fix by CVE-2021-29477.
9
10(cherry picked from commit 1ddecf1958924b178b76a31d989ef1e05af81964)
11
12
13CVE: CVE-2021-32625
14Upstream-Status: Backport [e9a1438ac4c52aa68dfa2a8324b6419356842116]
15
16Signed-off-by: Tony Tascioglu <tony.tascioglu@windriver.com>
17---
18 src/t_string.c | 18 +++++++++++++++++-
19 1 file changed, 17 insertions(+), 1 deletion(-)
20
21diff --git a/src/t_string.c b/src/t_string.c
22index 490d5983a..587d3aeb8 100644
23--- a/src/t_string.c
24+++ b/src/t_string.c
25@@ -797,6 +797,12 @@ void stralgoLCS(client *c) {
26 goto cleanup;
27 }
28
29+ /* Detect string truncation or later overflows. */
30+ if (sdslen(a) >= UINT32_MAX-1 || sdslen(b) >= UINT32_MAX-1) {
31+ addReplyError(c, "String too long for LCS");
32+ goto cleanup;
33+ }
34+
35 /* Compute the LCS using the vanilla dynamic programming technique of
36 * building a table of LCS(x,y) substrings. */
37 uint32_t alen = sdslen(a);
38@@ -805,9 +811,19 @@ void stralgoLCS(client *c) {
39 /* Setup an uint32_t array to store at LCS[i,j] the length of the
40 * LCS A0..i-1, B0..j-1. Note that we have a linear array here, so
41 * we index it as LCS[j+(blen+1)*j] */
42- uint32_t *lcs = zmalloc((size_t)(alen+1)*(blen+1)*sizeof(uint32_t));
43 #define LCS(A,B) lcs[(B)+((A)*(blen+1))]
44
45+ /* Try to allocate the LCS table, and abort on overflow or insufficient memory. */
46+ unsigned long long lcssize = (unsigned long long)(alen+1)*(blen+1); /* Can't overflow due to the size limits above. */
47+ unsigned long long lcsalloc = lcssize * sizeof(uint32_t);
48+ uint32_t *lcs = NULL;
49+ if (lcsalloc < SIZE_MAX && lcsalloc / lcssize == sizeof(uint32_t))
50+ lcs = ztrymalloc(lcsalloc);
51+ if (!lcs) {
52+ addReplyError(c, "Insufficient memory");
53+ goto cleanup;
54+ }
55+
56 /* Start building the LCS table. */
57 for (uint32_t i = 0; i <= alen; i++) {
58 for (uint32_t j = 0; j <= blen; j++) {
59--
602.32.0
61
diff --git a/meta-oe/recipes-extended/redis/redis_6.2.2.bb b/meta-oe/recipes-extended/redis/redis_6.2.6.bb
index 4317c10605..c129e61988 100644
--- a/meta-oe/recipes-extended/redis/redis_6.2.2.bb
+++ b/meta-oe/recipes-extended/redis/redis_6.2.6.bb
@@ -13,21 +13,8 @@ SRC_URI = "http://download.redis.io/releases/${BP}.tar.gz \
13 file://hiredis-use-default-CC-if-it-is-set.patch \ 13 file://hiredis-use-default-CC-if-it-is-set.patch \
14 file://lua-update-Makefile-to-use-environment-build-setting.patch \ 14 file://lua-update-Makefile-to-use-environment-build-setting.patch \
15 file://oe-use-libc-malloc.patch \ 15 file://oe-use-libc-malloc.patch \
16 file://0001-src-Do-not-reset-FINAL_LIBS.patch \
17 file://GNU_SOURCE.patch \
18 file://0006-Define-correct-gregs-for-RISCV32.patch \
19 file://fix-CVE-2021-29477.patch \
20 file://fix-CVE-2021-29478.patch \
21 file://fix-CVE-2021-32625.patch \
22 file://CVE-2021-32761.patch \
23 file://CVE-2021-41099.patch \
24 file://CVE-2021-32762.patch \
25 file://CVE-2021-32687.patch \
26 file://CVE-2021-32675.patch \
27 file://CVE-2021-32627-CVE-2021-32628.patch \
28 file://CVE-2021-32626.patch \
29 " 16 "
30SRC_URI[sha256sum] = "7a260bb74860f1b88c3d5942bf8ba60ca59f121c6dce42d3017bed6add0b9535" 17SRC_URI[sha256sum] = "5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab"
31 18
32inherit autotools-brokensep update-rc.d systemd useradd 19inherit autotools-brokensep update-rc.d systemd useradd
33 20