From 031bc65c20f349c3293ccca80fd98e22f259c60d Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Wed, 6 Apr 2022 18:05:26 +0300 Subject: [PATCH] lua: sandbox: relax the sandbox to allow more functionality in scripts This enables the debug and coroutine libraries and some more functions that are not really so risky to have around Related to #121 --- .../module-lua-scripting/wplua/sandbox.lua | 111 +++++++----------- modules/module-lua-scripting/wplua/wplua.c | 2 +- 2 files changed, 43 insertions(+), 70 deletions(-) diff --git a/modules/module-lua-scripting/wplua/sandbox.lua b/modules/module-lua-scripting/wplua/sandbox.lua index 67c40009..cb49e9e5 100644 --- a/modules/module-lua-scripting/wplua/sandbox.lua +++ b/modules/module-lua-scripting/wplua/sandbox.lua @@ -11,72 +11,51 @@ local SANDBOX_CONFIG = ... local SANDBOX_ENV = {} -local function populate_env(id) - local module, method = id:match('([^%.]+)%.([^%.]+)') - if module then - SANDBOX_ENV[module] = SANDBOX_ENV[module] or {} - SANDBOX_ENV[module][method] = _G[module][method] - else - SANDBOX_ENV[id] = _G[id] +function create_sandbox_env() + local function populate_env(id) + local module, method = id:match('([^%.]+)%.([^%.]+)') + if module then + SANDBOX_ENV[module] = SANDBOX_ENV[module] or {} + SANDBOX_ENV[module][method] = _G[module][method] + else + SANDBOX_ENV[id] = _G[id] + end end -end --- List of safe functions and packages -if SANDBOX_CONFIG["minimal_std"] then - -- minimal list, used for config files - ([[ - _VERSION ipairs pairs select tonumber tostring type + if not SANDBOX_ENV._VERSION then + -- List of exported functions and packages + ([[ _VERSION assert error ipairs next pairs tonumber + pcall select print tostring type xpcall require + table string math package utf8 debug coroutine + os.clock os.difftime os.time os.date os.getenv + ]]):gsub('%S+', populate_env) - table - - string.byte string.char string.find string.format string.gmatch - string.gsub string.len string.lower string.match string.reverse - string.sub string.upper - - ]]):gsub('%S+', populate_env) -else - -- full list, used for scripts - ([[ - _VERSION assert error ipairs next pairs print - pcall select tonumber tostring type xpcall require - - table utf8 - - math.abs math.acos math.asin math.atan math.ceil - math.cos math.deg math.exp math.tointeger math.floor math.fmod - math.huge math.ult math.log math.maxinteger math.mininteger math.max - math.min math.modf math.pi math.rad math.random - math.sin math.sqrt math.tan math.type - - string.byte string.char string.find string.format string.gmatch - string.gsub string.len string.lower string.match string.reverse - string.sub string.upper - - os.clock os.difftime os.time os.date os.getenv - - ]]):gsub('%S+', populate_env) -end - --- Additionally export everything in SANDBOX_EXPORT -if type(SANDBOX_EXPORT) == "table" then - for k, v in pairs(SANDBOX_EXPORT) do - SANDBOX_ENV[k] = v - end -end - --- Additionally protect packages from malicious scripts trying to override methods -for k, v in pairs(SANDBOX_ENV) do - if type(v) == "table" then - SANDBOX_ENV[k] = setmetatable({}, { - __index = v, - __newindex = function(_, attr_name, _) - error('Can not modify ' .. k .. '.' .. attr_name .. '. Protected by the sandbox.') + -- Additionally export everything in SANDBOX_EXPORT + if type(SANDBOX_EXPORT) == "table" then + for k, v in pairs(SANDBOX_EXPORT) do + SANDBOX_ENV[k] = v end - }) - end -end + end -populate_env("package") + -- Additionally protect packages from malicious scripts trying to override methods + for k, v in pairs(SANDBOX_ENV) do + if type(v) == "table" then + SANDBOX_ENV[k] = setmetatable({}, { + __index = v, + __newindex = function(_, attr_name, _) + error('Can not modify ' .. k .. '.' .. attr_name .. '. Protected by the sandbox.') + end + }) + end + end + end + + -- chunk's environment will be an empty table with __index + -- to access our SANDBOX_ENV (without being able to write it) + return setmetatable({}, { + __index = SANDBOX_ENV, + }) +end if SANDBOX_CONFIG["isolate_env"] then -- in isolate_env mode, use a separate enviornment for each loaded chunk and @@ -84,11 +63,7 @@ if SANDBOX_CONFIG["isolate_env"] then SANDBOX_ENV_LIST = {} function sandbox(chunk, ...) - -- chunk's environment will be an empty table with __index - -- to access our SANDBOX_ENV (without being able to write it) - local env = setmetatable({}, { - __index = SANDBOX_ENV, - }) + local env = create_sandbox_env() -- store the chunk's environment so that it is not garbage collected table.insert(SANDBOX_ENV_LIST, env) -- set it as the chunk's 1st upvalue (__ENV) @@ -100,9 +75,7 @@ else -- in common_env mode, use the same environment for all loaded chunks -- chunk's environment will be an empty table with __index -- to access our SANDBOX_ENV (without being able to write it) - SANDBOX_COMMON_ENV = setmetatable({}, { - __index = SANDBOX_ENV, - }) + SANDBOX_COMMON_ENV = create_sandbox_env() function sandbox(chunk, ...) -- set it as the chunk's 1st upvalue (__ENV) diff --git a/modules/module-lua-scripting/wplua/wplua.c b/modules/module-lua-scripting/wplua/wplua.c index 18f942f1..b33960dd 100644 --- a/modules/module-lua-scripting/wplua/wplua.c +++ b/modules/module-lua-scripting/wplua/wplua.c @@ -24,7 +24,7 @@ _wplua_openlibs (lua_State *L) static const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, - /* {LUA_COLIBNAME, luaopen_coroutine}, */ + {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, /* {LUA_IOLIBNAME, luaopen_io}, */ {LUA_OSLIBNAME, luaopen_os},