2

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?

marsgpl
  • 552
  • 2
  • 12

1 Answers1

4

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.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • oh, wait, script will be able to do this: _G.package = 123, because _G will be passed by reference, when I will access it like this: _ENV._G – marsgpl Jan 05 '16 at 01:14
  • 1
    Don't forget setting the __metatable field so they can't ```getmetatable(env).__index```. – warspyking Jan 05 '16 at 10:34