diff options
| author | Vijay Anusuri <vanusuri@mvista.com> | 2025-10-16 15:40:18 +0530 |
|---|---|---|
| committer | Gyorgy Sarvari <skandigraun@gmail.com> | 2025-10-17 10:51:27 +0200 |
| commit | abe7f83cc6316818b31d44022ad50fa94117300f (patch) | |
| tree | 815588022c3a010efe4d79363497b905493dc01b | |
| parent | 4450ab743041b883388fdf37b574e609143040f2 (diff) | |
| download | meta-openembedded-abe7f83cc6316818b31d44022ad50fa94117300f.tar.gz | |
redis: Fix CVE-2025-46818
Upstream-Status: Backport from https://github.com/redis/redis/commit/dccb672d838f05c940f040c27b74fde6fb47b2a7
Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
| -rw-r--r-- | meta-oe/recipes-extended/redis/redis-7.0.13/CVE-2025-46818.patch | 283 | ||||
| -rw-r--r-- | meta-oe/recipes-extended/redis/redis_7.0.13.bb | 1 |
2 files changed, 284 insertions, 0 deletions
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 @@ | |||
| 1 | From dccb672d838f05c940f040c27b74fde6fb47b2a7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Ozan Tezcan <ozantezcan@gmail.com> | ||
| 3 | Date: Mon, 23 Jun 2025 12:10:12 +0300 | ||
| 4 | Subject: [PATCH] Lua script can be executed in the context of another user | ||
| 5 | (CVE-2025-46818) | ||
| 6 | |||
| 7 | Upstream-Status: Backport [https://github.com/redis/redis/commit/dccb672d838f05c940f040c27b74fde6fb47b2a7] | ||
| 8 | CVE: CVE-2025-46818 | ||
| 9 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 10 | --- | ||
| 11 | src/config.c | 1 + | ||
| 12 | src/eval.c | 2 ++ | ||
| 13 | src/function_lua.c | 2 ++ | ||
| 14 | src/script_lua.c | 59 +++++++++++++++++++++++++++++---- | ||
| 15 | src/script_lua.h | 1 + | ||
| 16 | src/server.h | 1 + | ||
| 17 | tests/unit/scripting.tcl | 70 ++++++++++++++++++++++++++++++++++++++++ | ||
| 18 | 7 files changed, 129 insertions(+), 7 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/src/config.c b/src/config.c | ||
| 21 | index bfb49ef..d232eaf 100644 | ||
| 22 | --- a/src/config.c | ||
| 23 | +++ b/src/config.c | ||
| 24 | @@ -3011,6 +3011,7 @@ standardConfig static_configs[] = { | ||
| 25 | createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL), | ||
| 26 | createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled), | ||
| 27 | createBoolConfig("replica-ignore-disk-write-errors", NULL, MODIFIABLE_CONFIG, server.repl_ignore_disk_write_error, 0, NULL, NULL), | ||
| 28 | + createBoolConfig("lua-enable-deprecated-api", NULL, IMMUTABLE_CONFIG | HIDDEN_CONFIG, server.lua_enable_deprecated_api, 0, NULL, NULL), | ||
| 29 | |||
| 30 | /* String Configs */ | ||
| 31 | createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL), | ||
| 32 | diff --git a/src/eval.c b/src/eval.c | ||
| 33 | index a562335..f39ccc9 100644 | ||
| 34 | --- a/src/eval.c | ||
| 35 | +++ b/src/eval.c | ||
| 36 | @@ -261,6 +261,8 @@ void scriptingInit(int setup) { | ||
| 37 | /* Recursively lock all tables that can be reached from the global table */ | ||
| 38 | luaSetTableProtectionRecursively(lua); | ||
| 39 | lua_pop(lua, 1); | ||
| 40 | + /* Set metatables of basic types (string, number, nil etc.) readonly. */ | ||
| 41 | + luaSetTableProtectionForBasicTypes(lua); | ||
| 42 | |||
| 43 | lctx.lua = lua; | ||
| 44 | } | ||
| 45 | diff --git a/src/function_lua.c b/src/function_lua.c | ||
| 46 | index aedadb0..9450437 100644 | ||
| 47 | --- a/src/function_lua.c | ||
| 48 | +++ b/src/function_lua.c | ||
| 49 | @@ -490,6 +490,8 @@ int luaEngineInitEngine() { | ||
| 50 | lua_enablereadonlytable(lua_engine_ctx->lua, -1, 1); /* protect the new global table */ | ||
| 51 | lua_replace(lua_engine_ctx->lua, LUA_GLOBALSINDEX); /* set new global table as the new globals */ | ||
| 52 | |||
| 53 | + /* Set metatables of basic types (string, number, nil etc.) readonly. */ | ||
| 54 | + luaSetTableProtectionForBasicTypes(lua_engine_ctx->lua); | ||
| 55 | |||
| 56 | engine *lua_engine = zmalloc(sizeof(*lua_engine)); | ||
| 57 | *lua_engine = (engine) { | ||
| 58 | diff --git a/src/script_lua.c b/src/script_lua.c | ||
| 59 | index 33ed2aa..25a798f 100644 | ||
| 60 | --- a/src/script_lua.c | ||
| 61 | +++ b/src/script_lua.c | ||
| 62 | @@ -65,7 +65,6 @@ static char *redis_api_allow_list[] = { | ||
| 63 | static char *lua_builtins_allow_list[] = { | ||
| 64 | "xpcall", | ||
| 65 | "tostring", | ||
| 66 | - "getfenv", | ||
| 67 | "setmetatable", | ||
| 68 | "next", | ||
| 69 | "assert", | ||
| 70 | @@ -86,15 +85,16 @@ static char *lua_builtins_allow_list[] = { | ||
| 71 | "loadstring", | ||
| 72 | "ipairs", | ||
| 73 | "_VERSION", | ||
| 74 | - "setfenv", | ||
| 75 | "load", | ||
| 76 | "error", | ||
| 77 | NULL, | ||
| 78 | }; | ||
| 79 | |||
| 80 | -/* Lua builtins which are not documented on the Lua documentation */ | ||
| 81 | -static char *lua_builtins_not_documented_allow_list[] = { | ||
| 82 | +/* Lua builtins which are deprecated for sandboxing concerns */ | ||
| 83 | +static char *lua_builtins_deprecated[] = { | ||
| 84 | "newproxy", | ||
| 85 | + "setfenv", | ||
| 86 | + "getfenv", | ||
| 87 | NULL, | ||
| 88 | }; | ||
| 89 | |||
| 90 | @@ -116,7 +116,6 @@ static char **allow_lists[] = { | ||
| 91 | libraries_allow_list, | ||
| 92 | redis_api_allow_list, | ||
| 93 | lua_builtins_allow_list, | ||
| 94 | - lua_builtins_not_documented_allow_list, | ||
| 95 | lua_builtins_removed_after_initialization_allow_list, | ||
| 96 | NULL, | ||
| 97 | }; | ||
| 98 | @@ -1323,7 +1322,22 @@ static int luaNewIndexAllowList(lua_State *lua) { | ||
| 99 | break; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | - if (!*allow_l) { | ||
| 103 | + | ||
| 104 | + int allowed = (*allow_l != NULL); | ||
| 105 | + /* If not explicitly allowed, check if it's a deprecated function. If so, | ||
| 106 | + * allow it only if 'lua_enable_deprecated_api' config is enabled. */ | ||
| 107 | + int deprecated = 0; | ||
| 108 | + if (!allowed) { | ||
| 109 | + char **c = lua_builtins_deprecated; | ||
| 110 | + for (; *c; ++c) { | ||
| 111 | + if (strcmp(*c, variable_name) == 0) { | ||
| 112 | + deprecated = 1; | ||
| 113 | + allowed = server.lua_enable_deprecated_api ? 1 : 0; | ||
| 114 | + break; | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + } | ||
| 118 | + if (!allowed) { | ||
| 119 | /* Search the value on the back list, if its there we know that it was removed | ||
| 120 | * on purpose and there is no need to print a warning. */ | ||
| 121 | char **c = deny_list; | ||
| 122 | @@ -1332,7 +1346,7 @@ static int luaNewIndexAllowList(lua_State *lua) { | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | - if (!*c) { | ||
| 127 | + if (!*c && !deprecated) { | ||
| 128 | 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); | ||
| 129 | } | ||
| 130 | } else { | ||
| 131 | @@ -1384,6 +1398,37 @@ void luaSetTableProtectionRecursively(lua_State *lua) { | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | +/* Set the readonly flag on the metatable of basic types (string, nil etc.) */ | ||
| 136 | +void luaSetTableProtectionForBasicTypes(lua_State *lua) { | ||
| 137 | + static const int types[] = { | ||
| 138 | + LUA_TSTRING, | ||
| 139 | + LUA_TNUMBER, | ||
| 140 | + LUA_TBOOLEAN, | ||
| 141 | + LUA_TNIL, | ||
| 142 | + LUA_TFUNCTION, | ||
| 143 | + LUA_TTHREAD, | ||
| 144 | + LUA_TLIGHTUSERDATA | ||
| 145 | + }; | ||
| 146 | + | ||
| 147 | + for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); i++) { | ||
| 148 | + /* Push a dummy value of the type to get its metatable */ | ||
| 149 | + switch (types[i]) { | ||
| 150 | + case LUA_TSTRING: lua_pushstring(lua, ""); break; | ||
| 151 | + case LUA_TNUMBER: lua_pushnumber(lua, 0); break; | ||
| 152 | + case LUA_TBOOLEAN: lua_pushboolean(lua, 0); break; | ||
| 153 | + case LUA_TNIL: lua_pushnil(lua); break; | ||
| 154 | + case LUA_TFUNCTION: lua_pushcfunction(lua, NULL); break; | ||
| 155 | + case LUA_TTHREAD: lua_newthread(lua); break; | ||
| 156 | + case LUA_TLIGHTUSERDATA: lua_pushlightuserdata(lua, (void*)lua); break; | ||
| 157 | + } | ||
| 158 | + if (lua_getmetatable(lua, -1)) { | ||
| 159 | + luaSetTableProtectionRecursively(lua); | ||
| 160 | + lua_pop(lua, 1); /* pop metatable */ | ||
| 161 | + } | ||
| 162 | + lua_pop(lua, 1); /* pop dummy value */ | ||
| 163 | + } | ||
| 164 | +} | ||
| 165 | + | ||
| 166 | void luaRegisterVersion(lua_State* lua) { | ||
| 167 | lua_pushstring(lua,"REDIS_VERSION_NUM"); | ||
| 168 | lua_pushnumber(lua,REDIS_VERSION_NUM); | ||
| 169 | diff --git a/src/script_lua.h b/src/script_lua.h | ||
| 170 | index 4c2b348..d8a3688 100644 | ||
| 171 | --- a/src/script_lua.h | ||
| 172 | +++ b/src/script_lua.h | ||
| 173 | @@ -71,6 +71,7 @@ void luaRegisterGlobalProtectionFunction(lua_State *lua); | ||
| 174 | void luaSetErrorMetatable(lua_State *lua); | ||
| 175 | void luaSetAllowListProtection(lua_State *lua); | ||
| 176 | void luaSetTableProtectionRecursively(lua_State *lua); | ||
| 177 | +void luaSetTableProtectionForBasicTypes(lua_State *lua); | ||
| 178 | void luaRegisterLogFunction(lua_State* lua); | ||
| 179 | void luaRegisterVersion(lua_State* lua); | ||
| 180 | void luaPushErrorBuff(lua_State *lua, sds err_buff); | ||
| 181 | diff --git a/src/server.h b/src/server.h | ||
| 182 | index 82e4db9..952135f 100644 | ||
| 183 | --- a/src/server.h | ||
| 184 | +++ b/src/server.h | ||
| 185 | @@ -1900,6 +1900,7 @@ struct redisServer { | ||
| 186 | mstime_t busy_reply_threshold; /* Script / module timeout in milliseconds */ | ||
| 187 | int pre_command_oom_state; /* OOM before command (script?) was started */ | ||
| 188 | int script_disable_deny_script; /* Allow running commands marked "no-script" inside a script. */ | ||
| 189 | + int lua_enable_deprecated_api; /* Config to enable deprecated api */ | ||
| 190 | /* Lazy free */ | ||
| 191 | int lazyfree_lazy_eviction; | ||
| 192 | int lazyfree_lazy_expire; | ||
| 193 | diff --git a/tests/unit/scripting.tcl b/tests/unit/scripting.tcl | ||
| 194 | index d2fd6da..58f2028 100644 | ||
| 195 | --- a/tests/unit/scripting.tcl | ||
| 196 | +++ b/tests/unit/scripting.tcl | ||
| 197 | @@ -1021,6 +1021,27 @@ start_server {tags {"scripting"}} { | ||
| 198 | set _ $e | ||
| 199 | } {*Attempt to modify a readonly table*} | ||
| 200 | |||
| 201 | + test "Try trick readonly table on basic types metatable" { | ||
| 202 | + # Run the following scripts for basic types. Either getmetatable() | ||
| 203 | + # should return nil or the metatable must be readonly. | ||
| 204 | + set scripts { | ||
| 205 | + {getmetatable(nil).__index = function() return 1 end} | ||
| 206 | + {getmetatable('').__index = function() return 1 end} | ||
| 207 | + {getmetatable(123.222).__index = function() return 1 end} | ||
| 208 | + {getmetatable(true).__index = function() return 1 end} | ||
| 209 | + {getmetatable(function() return 1 end).__index = function() return 1 end} | ||
| 210 | + {getmetatable(coroutine.create(function() return 1 end)).__index = function() return 1 end} | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + foreach code $scripts { | ||
| 214 | + catch {run_script $code 0} e | ||
| 215 | + assert { | ||
| 216 | + [string match "*attempt to index a nil value script*" $e] || | ||
| 217 | + [string match "*Attempt to modify a readonly table*" $e] | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | test "Test loadfile are not available" { | ||
| 223 | catch { | ||
| 224 | run_script { | ||
| 225 | @@ -1049,6 +1070,55 @@ start_server {tags {"scripting"}} { | ||
| 226 | } {*Script attempted to access nonexistent global variable 'print'*} | ||
| 227 | } | ||
| 228 | |||
| 229 | +# Start a new server to test lua-enable-deprecated-api config | ||
| 230 | +foreach enabled {no yes} { | ||
| 231 | +start_server [subst {tags {"scripting external:skip"} overrides {lua-enable-deprecated-api $enabled}}] { | ||
| 232 | + test "Test setfenv availability lua-enable-deprecated-api=$enabled" { | ||
| 233 | + catch { | ||
| 234 | + run_script { | ||
| 235 | + local f = function() return 1 end | ||
| 236 | + setfenv(f, {}) | ||
| 237 | + return 0 | ||
| 238 | + } 0 | ||
| 239 | + } e | ||
| 240 | + if {$enabled} { | ||
| 241 | + assert_equal $e 0 | ||
| 242 | + } else { | ||
| 243 | + assert_match {*Script attempted to access nonexistent global variable 'setfenv'*} $e | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + test "Test getfenv availability lua-enable-deprecated-api=$enabled" { | ||
| 248 | + catch { | ||
| 249 | + run_script { | ||
| 250 | + local f = function() return 1 end | ||
| 251 | + getfenv(f) | ||
| 252 | + return 0 | ||
| 253 | + } 0 | ||
| 254 | + } e | ||
| 255 | + if {$enabled} { | ||
| 256 | + assert_equal $e 0 | ||
| 257 | + } else { | ||
| 258 | + assert_match {*Script attempted to access nonexistent global variable 'getfenv'*} $e | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + test "Test newproxy availability lua-enable-deprecated-api=$enabled" { | ||
| 263 | + catch { | ||
| 264 | + run_script { | ||
| 265 | + getmetatable(newproxy(true)).__gc = function() return 1 end | ||
| 266 | + return 0 | ||
| 267 | + } 0 | ||
| 268 | + } e | ||
| 269 | + if {$enabled} { | ||
| 270 | + assert_equal $e 0 | ||
| 271 | + } else { | ||
| 272 | + assert_match {*Script attempted to access nonexistent global variable 'newproxy'*} $e | ||
| 273 | + } | ||
| 274 | + } | ||
| 275 | +} | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | # Start a new server since the last test in this stanza will kill the | ||
| 279 | # instance at all. | ||
| 280 | start_server {tags {"scripting"}} { | ||
| 281 | -- | ||
| 282 | 2.25.1 | ||
| 283 | |||
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 \ | |||
| 28 | file://CVE-2025-32023.patch \ | 28 | file://CVE-2025-32023.patch \ |
| 29 | file://CVE-2025-48367.patch \ | 29 | file://CVE-2025-48367.patch \ |
| 30 | file://CVE-2025-46817.patch \ | 30 | file://CVE-2025-46817.patch \ |
| 31 | file://CVE-2025-46818.patch \ | ||
| 31 | " | 32 | " |
| 32 | SRC_URI[sha256sum] = "97065774d5fb8388eb0d8913458decfcb167d356e40d31dd01cd30c1cc391673" | 33 | SRC_URI[sha256sum] = "97065774d5fb8388eb0d8913458decfcb167d356e40d31dd01cd30c1cc391673" |
| 33 | 34 | ||
