CVE-2018-11218: Out-of-bounds Write (CWE-787)
value: Memory Corruption was discovered in the cmsgpack library in the Lua subsystem in Redis before 3.2.12, 4.x before 4.0.10, and 5.x before 5.0 RC2 because of stack-based buffer overflows.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2018-06-17T17:29Z
Repository: https://github.com/antirez/redis
Language: C
Files changed: deps/lua/src/lua_cmsgpack.c
Commit date: 2018-06-13 12:40:33 +0200
Commit message: Security: more cmsgpack fixes by @soloestoy.

@soloestoy sent me this additional fixes, after searching for similar
problems to the one reported in mp_pack(). I'm committing the changes
because it was not possible during to make a public PR to protect Redis
users and give Redis providers some time to patch their systems.

Diff: diff --git a/deps/lua/src/lua_cmsgpack.c b/deps/lua/src/lua_cmsgpack.c
index ba75ed455..892154793 100644
--- a/deps/lua/src/lua_cmsgpack.c
+++ b/deps/lua/src/lua_cmsgpack.c
@@ -383,10 +383,11 @@ void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) {
 #else
     size_t len = lua_rawlen(L,-1), j;
 #endif
 
     mp_encode_array(L,buf,len);
+    luaL_checkstack(L, 1, "in function mp_encode_lua_table_as_array");
     for (j = 1; j <= len; j++) {
         lua_pushnumber(L,j);
         lua_gettable(L,-2);
         mp_encode_lua_type(L,buf,level+1);
     }
@@ -398,10 +399,11 @@ void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) {
 
     /* First step: count keys into table. No other way to do it with the
      * Lua API, we need to iterate a first time. Note that an alternative
      * would be to do a single run, and then hack the buffer to insert the
      * map opcodes for message pack. Too hackish for this lib. */
+    luaL_checkstack(L, 3, "in function mp_encode_lua_table_as_map");
     lua_pushnil(L);
     while(lua_next(L,-2)) {
         lua_pop(L,1); /* remove value, keep key for next iteration. */
         len++;
     }
@@ -520,10 +522,11 @@ int mp_pack(lua_State *L) {
 
     buf = mp_buf_new(L);
     for(i = 1; i <= nargs; i++) {
         /* Copy argument i to top of stack for _encode processing;
          * the encode function pops it from the stack when complete. */
+        luaL_checkstack(L, 1, "in function mp_check");
         lua_pushvalue(L, i);
 
         mp_encode_lua_type(L,buf,0);
 
         lua_pushlstring(L,(char*)buf->b,buf->len);
@@ -548,10 +551,11 @@ void mp_decode_to_lua_type(lua_State *L, mp_cur *c);
 void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) {
     assert(len <= UINT_MAX);
     int index = 1;
 
     lua_newtable(L);
+    luaL_checkstack(L, 1, "in function mp_decode_to_lua_array");
     while(len--) {
         lua_pushnumber(L,index++);
         mp_decode_to_lua_type(L,c);
         if (c->err) return;
         lua_settable(L,-3);
@@ -822,10 +826,13 @@ int mp_unpack_full(lua_State *L, int limit, int offset) {
     if (!decode_all) {
         /* c->left is the remaining size of the input buffer.
          * subtract the entire buffer size from the unprocessed size
          * to get our next start offset */
         int offset = len - c.left;
+
+        luaL_checkstack(L, 1, "in function mp_unpack_full");
+
         /* Return offset -1 when we have have processed the entire buffer. */
         lua_pushinteger(L, c.left == 0 ? -1 : offset);
         /* Results are returned with the arg elements still
          * in place. Lua takes care of only returning
          * elements above the args for us.

Fixed code:     luaL_checkstack(L, 1, "in function mp_encode_lua_table_as_array");
    luaL_checkstack(L, 3, "in function mp_encode_lua_table_as_map");
        luaL_checkstack(L, 1, "in function mp_check");
    luaL_checkstack(L, 1, "in function mp_decode_to_lua_array");

        luaL_checkstack(L, 1, "in function mp_unpack_full");