Lua 5.3.2
I have a service written in Lua/C, that executes lua files in the same Lua_State.
I need to provide all the standard libraries for the file execution environment.
The simplest thing is to execute files this way: loadfile(file_path, "bt", _G)
The problem is: code in the file is able to corrupt the service's global state, so this method is not secure.
So, I need to create a sandboxed environment loadfile(file_path, "bt", env)
The question: how to register all the standard libraries from linit.c in the env
variable?
I can simply register all the libs from the linit.c, except luaopen_base, because it contains lua_pushglobaltable
I thought about this:
local env = {}
for k,v in pairs(_G) do
if type(v)=="function" then
env[k] = v
end
end
But it looks like a pathetic decision. Is anyone have a better solution?
The easiest way is to make env
inherit from _G
:
setmetatable(env,{__index=_G})
Everything in _G
will be seen in env
, but if you write to env
by creating a global variable, it won't affect _G
, which seems to be what you want.
Unfortunately, _G
itself is seen in _G
and so could be used to write to the original environment by doing things like _G.print=anyvalue
.
To protect _G
, add:
env._G = env
Unfortunately, the original _G
remains available via package.loaded._G
. This is harder to protect if you want to give access to package
. The easiest way is to deep copy _G.package
to env.package
and change env.package.loaded._G=env
.