From 71a07e9c929b3ae7b40fc715f674e41326e07404 Mon Sep 17 00:00:00 2001 From: houyingchao <1348375921@qq.com> Date: Thu, 14 Oct 2021 14:50:50 +0800 Subject: [PATCH] fix CVE-2021-32626 --- CVE-2021-32626-1.patch | 87 +++++++++++++++++++++++++++++++++++++ CVE-2021-32626-2.patch | 96 +++++++++++++++++++++++++++++++++++++++++ CVE-2021-32626-3.patch | 97 ++++++++++++++++++++++++++++++++++++++++++ redis.spec | 11 ++++- 4 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 CVE-2021-32626-1.patch create mode 100644 CVE-2021-32626-2.patch create mode 100644 CVE-2021-32626-3.patch diff --git a/CVE-2021-32626-1.patch b/CVE-2021-32626-1.patch new file mode 100644 index 0000000..dc28cf6 --- /dev/null +++ b/CVE-2021-32626-1.patch @@ -0,0 +1,87 @@ +From a1feda2388d556e6bc0c2f831e0b2f90f5f71abd Mon Sep 17 00:00:00 2001 +From: antirez +Date: Mon, 26 Nov 2018 16:44:00 +0100 +Subject: [PATCH 1/1] RESP3: Scripting RESP3 mode set/map protocol -> Lua + conversion. + +--- + src/scripting.c | 44 +++++++++++++++++++++++++++++++------------- + 1 file changed, 31 insertions(+), 13 deletions(-) + +diff --git a/src/scripting.c b/src/scripting.c +index 7aedc9deb..9b8d5fd30 100644 +--- a/src/scripting.c ++++ b/src/scripting.c +@@ -42,7 +42,7 @@ char *redisProtocolToLuaType_Int(lua_State *lua, char *reply); + char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply); + char *redisProtocolToLuaType_Status(lua_State *lua, char *reply); + char *redisProtocolToLuaType_Error(lua_State *lua, char *reply); +-char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply); ++char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply, int atype); + int redis_math_random (lua_State *L); + int redis_math_randomseed (lua_State *L); + void ldbInit(void); +@@ -132,7 +132,9 @@ char *redisProtocolToLuaType(lua_State *lua, char* reply) { + case '$': p = redisProtocolToLuaType_Bulk(lua,reply); break; + case '+': p = redisProtocolToLuaType_Status(lua,reply); break; + case '-': p = redisProtocolToLuaType_Error(lua,reply); break; +- case '*': p = redisProtocolToLuaType_MultiBulk(lua,reply); break; ++ case '*': p = redisProtocolToLuaType_MultiBulk(lua,reply,*p); break; ++ case '%': p = redisProtocolToLuaType_MultiBulk(lua,reply,*p); break; ++ case '~': p = redisProtocolToLuaType_MultiBulk(lua,reply,*p); break; + } + return p; + } +@@ -180,22 +182,38 @@ char *redisProtocolToLuaType_Error(lua_State *lua, char *reply) { + return p+2; + } + +-char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply) { ++char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply, int atype) { + char *p = strchr(reply+1,'\r'); + long long mbulklen; + int j = 0; + + string2ll(reply+1,p-reply-1,&mbulklen); +- p += 2; +- if (mbulklen == -1) { +- lua_pushboolean(lua,0); +- return p; +- } +- lua_newtable(lua); +- for (j = 0; j < mbulklen; j++) { +- lua_pushnumber(lua,j+1); +- p = redisProtocolToLuaType(lua,p); +- lua_settable(lua,-3); ++ if (server.lua_caller->resp == 2 || atype == '*') { ++ p += 2; ++ if (mbulklen == -1) { ++ lua_pushboolean(lua,0); ++ return p; ++ } ++ lua_newtable(lua); ++ for (j = 0; j < mbulklen; j++) { ++ lua_pushnumber(lua,j+1); ++ p = redisProtocolToLuaType(lua,p); ++ lua_settable(lua,-3); ++ } ++ } else if (server.lua_caller->resp == 3) { ++ /* Here we handle only Set and Map replies in RESP3 mode, since arrays ++ * follow the above RESP2 code path. */ ++ p += 2; ++ lua_newtable(lua); ++ for (j = 0; j < mbulklen; j++) { ++ p = redisProtocolToLuaType(lua,p); ++ if (atype == '%') { ++ p = redisProtocolToLuaType(lua,p); ++ } else { ++ lua_pushboolean(lua,1); ++ } ++ lua_settable(lua,-3); ++ } + } + return p; + } +-- +2.23.0 + diff --git a/CVE-2021-32626-2.patch b/CVE-2021-32626-2.patch new file mode 100644 index 0000000..433b2e7 --- /dev/null +++ b/CVE-2021-32626-2.patch @@ -0,0 +1,96 @@ +From 93c52ff5ff8145b570969f695e960cb502c79bb1 Mon Sep 17 00:00:00 2001 +From: antirez +Date: Fri, 13 Sep 2019 19:01:39 +0200 +Subject: [PATCH 1/1] RESP3: implement lua.setresp(). + +--- + src/scripting.c | 37 +++++++++++++++++++++++++++++++------ + 1 file changed, 31 insertions(+), 6 deletions(-) + +diff --git a/src/scripting.c b/src/scripting.c +index 032bfdf10..d5da14332 100644 +--- a/src/scripting.c ++++ b/src/scripting.c +@@ -42,7 +42,7 @@ char *redisProtocolToLuaType_Int(lua_State *lua, char *reply); + char *redisProtocolToLuaType_Bulk(lua_State *lua, char *reply); + char *redisProtocolToLuaType_Status(lua_State *lua, char *reply); + char *redisProtocolToLuaType_Error(lua_State *lua, char *reply); +-char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply, int atype); ++char *redisProtocolToLuaType_Aggregate(lua_State *lua, char *reply, int atype); + int redis_math_random (lua_State *L); + int redis_math_randomseed (lua_State *L); + void ldbInit(void); +@@ -132,9 +132,9 @@ char *redisProtocolToLuaType(lua_State *lua, char* reply) { + case '$': p = redisProtocolToLuaType_Bulk(lua,reply); break; + case '+': p = redisProtocolToLuaType_Status(lua,reply); break; + case '-': p = redisProtocolToLuaType_Error(lua,reply); break; +- case '*': p = redisProtocolToLuaType_MultiBulk(lua,reply,*p); break; +- case '%': p = redisProtocolToLuaType_MultiBulk(lua,reply,*p); break; +- case '~': p = redisProtocolToLuaType_MultiBulk(lua,reply,*p); break; ++ case '*': p = redisProtocolToLuaType_Aggregate(lua,reply,*p); break; ++ case '%': p = redisProtocolToLuaType_Aggregate(lua,reply,*p); break; ++ case '~': p = redisProtocolToLuaType_Aggregate(lua,reply,*p); break; + } + return p; + } +@@ -182,7 +182,7 @@ char *redisProtocolToLuaType_Error(lua_State *lua, char *reply) { + return p+2; + } + +-char *redisProtocolToLuaType_MultiBulk(lua_State *lua, char *reply, int atype) { ++char *redisProtocolToLuaType_Aggregate(lua_State *lua, char *reply, int atype) { + char *p = strchr(reply+1,'\r'); + long long mbulklen; + int j = 0; +@@ -859,6 +859,25 @@ int luaLogCommand(lua_State *lua) { + return 0; + } + ++/* redis.setresp() */ ++int luaSetResp(lua_State *lua) { ++ int argc = lua_gettop(lua); ++ ++ if (argc != 1) { ++ lua_pushstring(lua, "redis.setresp() requires one argument."); ++ return lua_error(lua); ++ } ++ ++ int resp = lua_tonumber(lua,-argc); ++ if (resp != 2 && resp != 3) { ++ lua_pushstring(lua, "RESP version must be 2 or 3."); ++ return lua_error(lua); ++ } ++ ++ server.lua_client->resp = resp; ++ return 0; ++} ++ + /* --------------------------------------------------------------------------- + * Lua engine initialization and reset. + * ------------------------------------------------------------------------- */ +@@ -986,6 +1005,11 @@ void scriptingInit(int setup) { + lua_pushcfunction(lua,luaLogCommand); + lua_settable(lua,-3); + ++ /* redis.setresp */ ++ lua_pushstring(lua,"setresp"); ++ lua_pushcfunction(lua,luaSetResp); ++ lua_settable(lua,-3); ++ + lua_pushstring(lua,"LOG_DEBUG"); + lua_pushnumber(lua,LL_DEBUG); + lua_settable(lua,-3); +@@ -1379,8 +1403,9 @@ void evalGenericCommand(client *c, int evalsha) { + luaSetGlobalArray(lua,"KEYS",c->argv+3,numkeys); + luaSetGlobalArray(lua,"ARGV",c->argv+3+numkeys,c->argc-3-numkeys); + +- /* Select the right DB in the context of the Lua client */ ++ /* Set the Lua client database and protocol. */ + selectDb(server.lua_client,c->db->id); ++ server.lua_client->resp = 2; /* Default is RESP2, scripts can change it. */ + + /* Set a hook in order to be able to stop the script execution if it + * is running for too much time. +-- +2.23.0 + diff --git a/CVE-2021-32626-3.patch b/CVE-2021-32626-3.patch new file mode 100644 index 0000000..6e6abdb --- /dev/null +++ b/CVE-2021-32626-3.patch @@ -0,0 +1,97 @@ +From 8f241ab3b8095186d008dbf78f0af90918f129bc Mon Sep 17 00:00:00 2001 +From: "meir@redislabs.com" +Date: Sun, 13 Jun 2021 14:27:18 +0300 +Subject: [PATCH] Fix invalid memory write on lua stack overflow + +--- + src/scripting.c | 39 +++++++++++++++++++++++++++++++++++++++ + 1 file changed, 39 insertions(+) + +diff --git a/src/scripting.c b/src/scripting.c +index a31852c..2b68ea5 100644 +--- a/src/scripting.c ++++ b/src/scripting.c +@@ -125,6 +125,16 @@ void sha1hex(char *digest, char *script, size_t len) { + */ + + char *redisProtocolToLuaType(lua_State *lua, char* reply) { ++ ++ if (!lua_checkstack(lua, 5)) { ++ /* ++ * Increase the Lua stack if needed, to make sure there is enough room ++ * to push 5 elements to the stack. On failure, exit with panic. ++ * Notice that we need, in the worst case, 5 elements because redisProtocolToLuaType_Aggregate ++ * might push 5 elements to the Lua stack.*/ ++ serverPanic("lua stack limit reach when parsing redis.call reply"); ++ } ++ + char *p = reply; + + switch(*p) { +@@ -210,6 +220,11 @@ char *redisProtocolToLuaType_Aggregate(lua_State *lua, char *reply, int atype) { + if (atype == '%') { + p = redisProtocolToLuaType(lua,p); + } else { ++ if (!lua_checkstack(lua, 1)) { ++ /* Notice that here we need to check the stack again because the recursive ++ * call to redisProtocolToLuaType might have use the room allocated in the stack */ ++ serverPanic("lua stack limit reach when parsing redis.call reply"); ++ } + lua_pushboolean(lua,1); + } + lua_settable(lua,-3); +@@ -293,6 +308,17 @@ void luaSortArray(lua_State *lua) { + * ------------------------------------------------------------------------- */ + + void luaReplyToRedisReply(client *c, lua_State *lua) { ++ ++ if (!lua_checkstack(lua, 4)) { ++ /* Increase the Lua stack if needed to make sure there is enough room ++ * to push 4 elements to the stack. On failure, return error. ++ * Notice that we need, in the worst case, 4 elements because returning a map might ++ * require push 4 elements to the Lua stack.*/ ++ addReplyErrorFormat(c, "reached lua stack limit"); ++ lua_pop(lua,1); /* pop the element from the stack */ ++ return; ++ } ++ + int t = lua_type(lua,-1); + + switch(t) { +@@ -310,6 +336,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) { + * Error are returned as a single element table with 'err' field. + * Status replies are returned as single element table with 'ok' + * field. */ ++ /* we took care of the stack size on function start */ + lua_pushstring(lua,"err"); + lua_gettable(lua,-2); + t = lua_type(lua,-1); +@@ -338,6 +365,7 @@ void luaReplyToRedisReply(client *c, lua_State *lua) { + + lua_pop(lua,1); /* Discard the 'ok' field value we popped */ + while(1) { ++ /* we took care of the stack size on function start */ + lua_pushnumber(lua,j++); + lua_gettable(lua,-2); + t = lua_type(lua,-1); +@@ -2240,6 +2268,17 @@ void ldbEval(lua_State *lua, sds *argv, int argc) { + void ldbRedis(lua_State *lua, sds *argv, int argc) { + int j, saved_rc = server.lua_replicate_commands; + ++ if (!lua_checkstack(lua, argc + 1)) { ++ /* Increase the Lua stack if needed to make sure there is enough room ++ * to push 'argc + 1' elements to the stack. On failure, return error. ++ * Notice that we need, in worst case, 'argc + 1' elements because we push all the arguments ++ * given by the user (without the first argument) and we also push the 'redis' global table and ++ * 'redis.call' function so: ++ * (1 (redis table)) + (1 (redis.call function)) + (argc - 1 (all arguments without the first)) = argc + 1*/ ++ ldbLogRedisReply("max lua stack reached"); ++ return; ++ } ++ + lua_getglobal(lua,"redis"); + lua_pushstring(lua,"call"); + lua_gettable(lua,-2); /* Stack: redis, redis.call */ +-- +2.23.0 + diff --git a/redis.spec b/redis.spec index f0a4795..069917a 100644 --- a/redis.spec +++ b/redis.spec @@ -1,6 +1,6 @@ Name: redis Version: 4.0.11 -Release: 18 +Release: 19 Summary: A persistent key-value database License: BSD and MIT URL: https://redis.io @@ -23,6 +23,9 @@ Patch0009: CVE-2021-21309.patch Patch0010: CVE-2021-3470.patch Patch0011: CVE-2021-29478.patch Patch0012: CVE-2021-32672.patch +Patch0013: CVE-2021-32626-1.patch +Patch0014: CVE-2021-32626-2.patch +Patch0015: CVE-2021-32626-3.patch BuildRequires: systemd gcc Requires: /bin/awk @@ -52,6 +55,9 @@ Redis is an advanced key-value store. It is often referred to as a dattructure s %patch0010 -p1 %patch0011 -p1 %patch0012 -p1 +%patch0013 -p1 +%patch0014 -p1 +%patch0015 -p1 sed -i -e 's|^logfile .*$|logfile /var/log/redis/redis.log|g' redis.conf sed -i -e '$ alogfile /var/log/redis/sentinel.log' sentinel.conf @@ -109,6 +115,9 @@ exit 0 %{_unitdir}/%{name}-sentinel.service %changelog +* Thu Oct 14 2021 houyingchao - 4.0.11-19 +- Fix CVE-2021-32626 + * Sat Oct 09 2021 yaoxin - 4.0.11-18 - Fix CVE-2021-32672 -- Gitee