diff mbox series

[meta-oe,kirkstone,5/7] redis: Fix CVE-2025-46818

Message ID 20251016101020.279084-5-vanusuri@mvista.com
State New
Headers show
Series [meta-oe,kirkstone,1/7] redis: Fix CVE-2025-27151 | expand

Commit Message

Vijay Anusuri Oct. 16, 2025, 10:10 a.m. UTC
From: Vijay Anusuri <vanusuri@mvista.com>

Upstream-Status: Backport from https://github.com/redis/redis/commit/dccb672d838f05c940f040c27b74fde6fb47b2a7

Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
---
 .../redis/redis-7.0.13/CVE-2025-46818.patch   | 283 ++++++++++++++++++
 .../recipes-extended/redis/redis_7.0.13.bb    |   1 +
 2 files changed, 284 insertions(+)
 create mode 100644 meta-oe/recipes-extended/redis/redis-7.0.13/CVE-2025-46818.patch
diff mbox series

Patch

diff --git a/meta-oe/recipes-extended/redis/redis-7.0.13/CVE-2025-46818.patch b/meta-oe/recipes-extended/redis/redis-7.0.13/CVE-2025-46818.patch
new file mode 100644
index 0000000000..0f7fc15cfc
--- /dev/null
+++ b/meta-oe/recipes-extended/redis/redis-7.0.13/CVE-2025-46818.patch
@@ -0,0 +1,283 @@ 
+From dccb672d838f05c940f040c27b74fde6fb47b2a7 Mon Sep 17 00:00:00 2001
+From: Ozan Tezcan <ozantezcan@gmail.com>
+Date: Mon, 23 Jun 2025 12:10:12 +0300
+Subject: [PATCH] Lua script can be executed in the context of another user
+ (CVE-2025-46818)
+
+Upstream-Status: Backport [https://github.com/redis/redis/commit/dccb672d838f05c940f040c27b74fde6fb47b2a7]
+CVE: CVE-2025-46818
+Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
+---
+ src/config.c             |  1 +
+ src/eval.c               |  2 ++
+ src/function_lua.c       |  2 ++
+ src/script_lua.c         | 59 +++++++++++++++++++++++++++++----
+ src/script_lua.h         |  1 +
+ src/server.h             |  1 +
+ tests/unit/scripting.tcl | 70 ++++++++++++++++++++++++++++++++++++++++
+ 7 files changed, 129 insertions(+), 7 deletions(-)
+
+diff --git a/src/config.c b/src/config.c
+index bfb49ef..d232eaf 100644
+--- a/src/config.c
++++ b/src/config.c
+@@ -3011,6 +3011,7 @@ standardConfig static_configs[] = {
+     createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL),
+     createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled),
+     createBoolConfig("replica-ignore-disk-write-errors", NULL, MODIFIABLE_CONFIG, server.repl_ignore_disk_write_error, 0, NULL, NULL),
++    createBoolConfig("lua-enable-deprecated-api", NULL, IMMUTABLE_CONFIG | HIDDEN_CONFIG, server.lua_enable_deprecated_api, 0, NULL, NULL),
+ 
+     /* String Configs */
+     createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL),
+diff --git a/src/eval.c b/src/eval.c
+index a562335..f39ccc9 100644
+--- a/src/eval.c
++++ b/src/eval.c
+@@ -261,6 +261,8 @@ void scriptingInit(int setup) {
+     /* Recursively lock all tables that can be reached from the global table */
+     luaSetTableProtectionRecursively(lua);
+     lua_pop(lua, 1);
++    /* Set metatables of basic types (string, number, nil etc.) readonly. */
++    luaSetTableProtectionForBasicTypes(lua);
+ 
+     lctx.lua = lua;
+ }
+diff --git a/src/function_lua.c b/src/function_lua.c
+index aedadb0..9450437 100644
+--- a/src/function_lua.c
++++ b/src/function_lua.c
+@@ -490,6 +490,8 @@ int luaEngineInitEngine() {
+     lua_enablereadonlytable(lua_engine_ctx->lua, -1, 1); /* protect the new global table */
+     lua_replace(lua_engine_ctx->lua, LUA_GLOBALSINDEX); /* set new global table as the new globals */
+ 
++    /* Set metatables of basic types (string, number, nil etc.) readonly. */
++    luaSetTableProtectionForBasicTypes(lua_engine_ctx->lua);
+ 
+     engine *lua_engine = zmalloc(sizeof(*lua_engine));
+     *lua_engine = (engine) {
+diff --git a/src/script_lua.c b/src/script_lua.c
+index 33ed2aa..25a798f 100644
+--- a/src/script_lua.c
++++ b/src/script_lua.c
+@@ -65,7 +65,6 @@ static char *redis_api_allow_list[] = {
+ static char *lua_builtins_allow_list[] = {
+     "xpcall",
+     "tostring",
+-    "getfenv",
+     "setmetatable",
+     "next",
+     "assert",
+@@ -86,15 +85,16 @@ static char *lua_builtins_allow_list[] = {
+     "loadstring",
+     "ipairs",
+     "_VERSION",
+-    "setfenv",
+     "load",
+     "error",
+     NULL,
+ };
+ 
+-/* Lua builtins which are not documented on the Lua documentation */
+-static char *lua_builtins_not_documented_allow_list[] = {
++/* Lua builtins which are deprecated for sandboxing concerns */
++static char *lua_builtins_deprecated[] = {
+     "newproxy",
++    "setfenv",
++    "getfenv",
+     NULL,
+ };
+ 
+@@ -116,7 +116,6 @@ static char **allow_lists[] = {
+     libraries_allow_list,
+     redis_api_allow_list,
+     lua_builtins_allow_list,
+-    lua_builtins_not_documented_allow_list,
+     lua_builtins_removed_after_initialization_allow_list,
+     NULL,
+ };
+@@ -1323,7 +1322,22 @@ static int luaNewIndexAllowList(lua_State *lua) {
+             break;
+         }
+     }
+-    if (!*allow_l) {
++
++    int allowed = (*allow_l != NULL);
++    /* If not explicitly allowed, check if it's a deprecated function. If so,
++     * allow it only if 'lua_enable_deprecated_api' config is enabled. */
++    int deprecated = 0;
++    if (!allowed) {
++        char **c = lua_builtins_deprecated;
++        for (; *c; ++c) {
++            if (strcmp(*c, variable_name) == 0) {
++                deprecated = 1;
++                allowed = server.lua_enable_deprecated_api ? 1 : 0;
++                break;
++            }
++        }
++    }
++    if (!allowed) {
+         /* Search the value on the back list, if its there we know that it was removed
+          * on purpose and there is no need to print a warning. */
+         char **c = deny_list;
+@@ -1332,7 +1346,7 @@ static int luaNewIndexAllowList(lua_State *lua) {
+                 break;
+             }
+         }
+-        if (!*c) {
++        if (!*c && !deprecated) {
+             serverLog(LL_WARNING, "A key '%s' was added to Lua globals which is not on the globals allow list nor listed on the deny list.", variable_name);
+         }
+     } else {
+@@ -1384,6 +1398,37 @@ void luaSetTableProtectionRecursively(lua_State *lua) {
+     }
+ }
+ 
++/* Set the readonly flag on the metatable of basic types (string, nil etc.) */
++void luaSetTableProtectionForBasicTypes(lua_State *lua) {
++    static const int types[] = {
++        LUA_TSTRING,
++        LUA_TNUMBER,
++        LUA_TBOOLEAN,
++        LUA_TNIL,
++        LUA_TFUNCTION,
++        LUA_TTHREAD,
++        LUA_TLIGHTUSERDATA
++    };
++
++    for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); i++) {
++        /* Push a dummy value of the type to get its metatable */
++        switch (types[i]) {
++            case LUA_TSTRING: lua_pushstring(lua, ""); break;
++            case LUA_TNUMBER: lua_pushnumber(lua, 0); break;
++            case LUA_TBOOLEAN: lua_pushboolean(lua, 0); break;
++            case LUA_TNIL: lua_pushnil(lua); break;
++            case LUA_TFUNCTION: lua_pushcfunction(lua, NULL); break;
++            case LUA_TTHREAD: lua_newthread(lua); break;
++            case LUA_TLIGHTUSERDATA: lua_pushlightuserdata(lua, (void*)lua); break;
++        }
++        if (lua_getmetatable(lua, -1)) {
++            luaSetTableProtectionRecursively(lua);
++            lua_pop(lua, 1); /* pop metatable */
++        }
++        lua_pop(lua, 1); /* pop dummy value */
++    }
++}
++
+ void luaRegisterVersion(lua_State* lua) {
+     lua_pushstring(lua,"REDIS_VERSION_NUM");
+     lua_pushnumber(lua,REDIS_VERSION_NUM);
+diff --git a/src/script_lua.h b/src/script_lua.h
+index 4c2b348..d8a3688 100644
+--- a/src/script_lua.h
++++ b/src/script_lua.h
+@@ -71,6 +71,7 @@ void luaRegisterGlobalProtectionFunction(lua_State *lua);
+ void luaSetErrorMetatable(lua_State *lua);
+ void luaSetAllowListProtection(lua_State *lua);
+ void luaSetTableProtectionRecursively(lua_State *lua);
++void luaSetTableProtectionForBasicTypes(lua_State *lua);
+ void luaRegisterLogFunction(lua_State* lua);
+ void luaRegisterVersion(lua_State* lua);
+ void luaPushErrorBuff(lua_State *lua, sds err_buff);
+diff --git a/src/server.h b/src/server.h
+index 82e4db9..952135f 100644
+--- a/src/server.h
++++ b/src/server.h
+@@ -1900,6 +1900,7 @@ struct redisServer {
+     mstime_t busy_reply_threshold;  /* Script / module timeout in milliseconds */
+     int pre_command_oom_state;         /* OOM before command (script?) was started */
+     int script_disable_deny_script;    /* Allow running commands marked "no-script" inside a script. */
++    int lua_enable_deprecated_api;     /* Config to enable deprecated api */
+     /* Lazy free */
+     int lazyfree_lazy_eviction;
+     int lazyfree_lazy_expire;
+diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl
+index d2fd6da..58f2028 100644
+--- a/tests/unit/scripting.tcl
++++ b/tests/unit/scripting.tcl
+@@ -1021,6 +1021,27 @@ start_server {tags {"scripting"}} {
+         set _ $e
+     } {*Attempt to modify a readonly table*}
+ 
++    test "Try trick readonly table on basic types metatable" {
++        # Run the following scripts for basic types. Either getmetatable()
++        # should return nil or the metatable must be readonly.
++        set scripts {
++            {getmetatable(nil).__index = function() return 1 end}
++            {getmetatable('').__index = function() return 1 end}
++            {getmetatable(123.222).__index = function() return 1 end}
++            {getmetatable(true).__index = function() return 1 end}
++            {getmetatable(function() return 1 end).__index = function() return 1 end}
++            {getmetatable(coroutine.create(function() return 1 end)).__index = function() return 1 end}
++        }
++
++        foreach code $scripts {
++            catch {run_script $code 0} e
++            assert {
++                [string match "*attempt to index a nil value script*" $e] ||
++                [string match "*Attempt to modify a readonly table*" $e]
++            }
++        }
++    }
++
+     test "Test loadfile are not available" {
+         catch {
+             run_script {
+@@ -1049,6 +1070,55 @@ start_server {tags {"scripting"}} {
+     } {*Script attempted to access nonexistent global variable 'print'*}
+ }
+ 
++# Start a new server to test lua-enable-deprecated-api config
++foreach enabled {no yes} {
++start_server [subst {tags {"scripting external:skip"} overrides {lua-enable-deprecated-api $enabled}}] {
++    test "Test setfenv availability lua-enable-deprecated-api=$enabled" {
++        catch {
++            run_script {
++                local f = function() return 1 end
++                setfenv(f, {})
++                return 0
++            } 0
++        } e
++        if {$enabled} {
++            assert_equal $e 0
++        } else {
++            assert_match {*Script attempted to access nonexistent global variable 'setfenv'*} $e
++        }
++    }
++
++    test "Test getfenv availability lua-enable-deprecated-api=$enabled" {
++        catch {
++            run_script {
++                local f = function() return 1 end
++                getfenv(f)
++                return 0
++            } 0
++        } e
++        if {$enabled} {
++            assert_equal $e 0
++        } else {
++            assert_match {*Script attempted to access nonexistent global variable 'getfenv'*} $e
++        }
++    }
++
++    test "Test newproxy availability lua-enable-deprecated-api=$enabled" {
++        catch {
++            run_script {
++                getmetatable(newproxy(true)).__gc = function() return 1 end
++                return 0
++            } 0
++        } e
++        if {$enabled} {
++            assert_equal $e 0
++        } else {
++            assert_match {*Script attempted to access nonexistent global variable 'newproxy'*} $e
++        }
++    }
++}
++}
++
+ # Start a new server since the last test in this stanza will kill the
+ # instance at all.
+ start_server {tags {"scripting"}} {
+-- 
+2.25.1
+
diff --git a/meta-oe/recipes-extended/redis/redis_7.0.13.bb b/meta-oe/recipes-extended/redis/redis_7.0.13.bb
index e3a302e582..be4e90564d 100644
--- a/meta-oe/recipes-extended/redis/redis_7.0.13.bb
+++ b/meta-oe/recipes-extended/redis/redis_7.0.13.bb
@@ -28,6 +28,7 @@  SRC_URI = "http://download.redis.io/releases/${BP}.tar.gz \
            file://CVE-2025-32023.patch \
            file://CVE-2025-48367.patch \
            file://CVE-2025-46817.patch \
+           file://CVE-2025-46818.patch \
            "
 SRC_URI[sha256sum] = "97065774d5fb8388eb0d8913458decfcb167d356e40d31dd01cd30c1cc391673"