You can set the function environment that you run the untrusted code in via setfenv(). Here's an outline:
local env = {ipairs}
setfenv(user_script, env)
pcall(user_script)
The user_script
function can only access what is in its environment. So you can then explicitly add in the functions that you want the untrusted code to have access to (whitelist). In this case the user script only has access to ipairs
but nothing else (dofile
, loadfile
, etc).
See Lua Sandboxes for an example and more information on lua sandboxing.
Here's a solution for Lua 5.2 (including a sample environment that would also work in 5.1):
-- save a pointer to globals that would be unreachable in sandbox
local e=_ENV
-- sample sandbox environment
sandbox_env = {
ipairs = ipairs,
next = next,
pairs = pairs,
pcall = pcall,
tonumber = tonumber,
tostring = tostring,
type = type,
unpack = unpack,
coroutine = { create = coroutine.create, resume = coroutine.resume,
running = coroutine.running, status = coroutine.status,
wrap = coroutine.wrap },
string = { byte = string.byte, char = string.char, find = string.find,
format = string.format, gmatch = string.gmatch, gsub = string.gsub,
len = string.len, lower = string.lower, match = string.match,
rep = string.rep, reverse = string.reverse, sub = string.sub,
upper = string.upper },
table = { insert = table.insert, maxn = table.maxn, remove = table.remove,
sort = table.sort },
math = { abs = math.abs, acos = math.acos, asin = math.asin,
atan = math.atan, atan2 = math.atan2, ceil = math.ceil, cos = math.cos,
cosh = math.cosh, deg = math.deg, exp = math.exp, floor = math.floor,
fmod = math.fmod, frexp = math.frexp, huge = math.huge,
ldexp = math.ldexp, log = math.log, log10 = math.log10, max = math.max,
min = math.min, modf = math.modf, pi = math.pi, pow = math.pow,
rad = math.rad, random = math.random, sin = math.sin, sinh = math.sinh,
sqrt = math.sqrt, tan = math.tan, tanh = math.tanh },
os = { clock = os.clock, difftime = os.difftime, time = os.time },
}
function run_sandbox(sb_env, sb_func, ...)
local sb_orig_env=_ENV
if (not sb_func) then return nil end
_ENV=sb_env
local sb_ret={e.pcall(sb_func, ...)}
_ENV=sb_orig_env
return e.table.unpack(sb_ret)
end
Then to use it, you would call your function (my_func
) like the following:
pcall_rc, result_or_err_msg = run_sandbox(sandbox_env, my_func, arg1, arg2)
The Lua live demo contains a (specialized) sandbox. The source is freely available.
One of the easiest ways to clear out undesirables is to first load a Lua script of your own devising, that does things like:
load = nil
loadfile = nil
dofile = nil
Alternatively, you can use setfenv
to create a restricted environment that you can insert specific safe functions into.
Totally safe sandboxing is a little harder. If you load code from anywhere, be aware that precompiled code can crash Lua. Even completely restricted code can go into an infinite loop and block indefinitely if you don't have system for shutting it down.
You can use the lua_setglobal
function provided by the Lua API to set those values in the global namespace to nil
which will effectively prevent any user scripts from being able to access them.
lua_pushnil(state_pointer);
lua_setglobal(state_pointer, "io");
lua_pushnil(state_pointer);
lua_setglobal(state_pointer, "loadfile");
...etc...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With