From c12805ecac6f1a041037afbf720f1ae4a33f4c43 Mon Sep 17 00:00:00 2001 From: "nstbayless@gmail.com" Date: Thu, 1 Oct 2026 17:40:46 -0700 Subject: [PATCH] remove some lua functions that break determinism or can be harmful --- src/config.c | 4 +-- src/lua_base.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/config.c b/src/config.c index dce8488627..5301cf1680 100644 --- a/src/config.c +++ b/src/config.c @@ -1254,8 +1254,8 @@ long get_rid(const struct NamedCommand *desc, const char *itmname) } if (strcasecmp("RANDOM", itmname) == 0) { - i = (rand() % i); - return desc[i].num; + int32_t idx = (int32_t)LbRandomSeries((uint32_t)i, &game.action_random_seed, __func__, __LINE__); + return desc[idx].num; } return -1; } diff --git a/src/lua_base.c b/src/lua_base.c index 88ef342bb6..df2b3a9e53 100644 --- a/src/lua_base.c +++ b/src/lua_base.c @@ -38,8 +38,51 @@ static int lua_disabled_os_function(lua_State *L) } +static void lua_blacklist(lua_State *L, const char *libname, const char *name) +{ + lua_getglobal(L, libname); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return; + } + lua_pushnil(L); + lua_setfield(L, -2, name); + lua_pop(L, 1); +} + +static void lua_whitelist(lua_State *L, const char *libname, const char *keep) +{ + lua_getglobal(L, libname); + if (!lua_istable(L, -1)) { + lua_pop(L, 1); + return; + } + int t = lua_gettop(L); + lua_pushnil(L); + while (lua_next(L, t) != 0) { + if (lua_type(L, -2) == LUA_TSTRING) { + const char *key = lua_tostring(L, -2); + if (strcmp(key, keep) != 0) { + lua_pushnil(L); + lua_setfield(L, t, key); + } + } + lua_pop(L, 1); + } + lua_pop(L, 1); +} + +// Remove Lua functions which can break the sandbox/determinism static void disable_lua_functions(lua_State *L) { + // TODO - remove/replace these + lua_whitelist(L, "io", "open"); + + // TODO - remove/replace these + lua_whitelist(L, "os", "remove"); + + lua_blacklist(L, "package", "loadlib"); + if (game.game_kind != GKind_MultiGame) { return; } @@ -293,11 +336,34 @@ static void open_lua_script_for_mod_all(lua_State* L, LevelNumber lvnum) /* @comment * The loading items of open_lua_script and open_lua_script_for_mod need to be consistent. */ +static void open_lua_standard_libraries(lua_State *L) +{ + static const luaL_Reg stdlib[] = { + {"", luaopen_base}, + {LUA_TABLIBNAME, luaopen_table}, + {LUA_IOLIBNAME, luaopen_io}, + {LUA_OSLIBNAME, luaopen_os}, + {LUA_STRLIBNAME, luaopen_string}, + {LUA_MATHLIBNAME, luaopen_math}, + {LUA_DBLIBNAME, luaopen_debug}, + {LUA_LOADLIBNAME, luaopen_package}, + {LUA_BITLIBNAME, luaopen_bit}, + // {LUA_JITLIBNAME, luaopen_jit}, + // {LUA_FFILIBNAME, luaopen_ffi}, + {NULL, NULL} + }; + for (const luaL_Reg *lib = stdlib; lib->func != NULL; lib++) { + lua_pushcfunction(L, lib->func); + lua_pushstring(L, lib->name); + lua_call(L, 1, 0); + } +} + TbBool open_lua_script(LevelNumber lvnum) { Lvl_script = luaL_newstate(); - luaL_openlibs(Lvl_script); + open_lua_standard_libraries(Lvl_script); disable_lua_functions(Lvl_script); lua_set_random_seed(game.action_random_seed);