Lua Sandbox with special features that

I am trying to use How to create a secure Lua sandbox? to create your own leaky sandbox.

I am trying to create a Lua sandbox where some Lua functions can access some other Lua functions outside the sandbox. For example, I want my sandbox to have a special "display" function that can cause "print", but also does not have a "print" in the sandbox.

The main problem is that I'm trying to create a sandbox in an already large code base, so I can’t forget about the functions.

How is this possible?

The solution should be a pure Lua function due to my malfunction.

+4
source share
3 answers

When you create a sandbox, you do this by selecting the functions and values ​​of the cherry from a larger environment to create a new sandbox environment. You do not need to destroy or "zero" anything in the source environment.

  • Create a sandbox environment using cherry capture features and values
  • Download the script (it will compile it and return it as a function to call)
  • Install script environment in sandbox environment
  • Run the script in the sandbox

So,

local script = loadstring "display(math.log(2, 3))" local env = {display = print, math = math, string = string} setfenv(script, env) pcall(script) 

prints

 0.69314718055995 

whereas

 local script = loadstring "print(math.log(2, 3))" local env = {display = print, math = math, string = string} setfenv(script, env) pcall(script) 

not working with

 false [string "print(math.log(2, 3))"]:1: attempt to call global 'print' (a nil value) 
+5
source

Is it needed to call the function of the standard Lua print library? Can you emulate print functionality instead? Because that would be the easiest way.

However, if you want to have a wrapper around print , there are two ways to do this: with pure Lua code and with C / C ++ code.

The solution to pure Lua is as follows. Please note that this must be done before loading any external scripts. First open the standard Lua library, which has print . Then run this Lua script:

 local internal_print = print return function(...) --Do display logic. internal_print(...) --Or whatever else you want. end 

This will return the "display" function. You can save it in a global variable called display , if you want, or name something else.

After that, you can nil print the global variable print , making it almost completely inaccessible.

If you want to do this with C / C ++, this is very similar. First, as before, you register the standard Lua library, which includes print , so you can get a function for it. Then you use lua_getglobal(L, "print") to get the print function and push it lua_getglobal(L, "print") stack. Then you register your C / C ++ function with lua_pushcclosure . But you want to specify one upvalue that Lua pops off the stack during registration.

And now your registered function is on the stack, waiting to be injected into a Lua variable or global table entry.

Warning: the Lua debug library can call upvalues ​​and thus get the print function from your new function. Therefore, if you want excellent security, get rid of debug.getupvalue .

+1
source

Create your own sandbox (or several sandboxes if each one has different requirements) and move the untrusted code to the sandbox one fragment at a time. In my quick tests, cli, both 5.1 and 5.2 will run functions that were defined outside the sandbox without changes. To use the Doug example, suppose display is part of your pre-existing code that uses print :

 -- 5.1 local function display(...) print(...) end local script = loadstring "display(math.log(2, 3))" local env = {display = display, math = math, string = string} setfenv(script, env) print(pcall(script)) -- 5.2 local function display(...) print(...) end local script = loadstring "display(math.log(2, 3))" local e=_ENV _ENV={display = display, math = math, string = string} e.print(e.pcall(script)) _ENV=e 

Please note that in both of the above examples, the display function uses print without changing this code, since you were not in the sandbox when this function was created.

In the past, I saved a local pointer to the environment without the sandbox, but I cannot reproduce the situation when it is necessary in my quick cli tests. If you can come up with an example, I might come up with a workaround for which the variable e is not required. Here is an example of this code using 5.2:

 local e=_ENV for k,v in e.pairs(value) do -- iterate end 

another example, for my read-only table code, I use e again:

 function ro_table (t) local t = t if t then return e.setmetatable({}, { __index=t, __newindex= function(_,_,_) e.error ("Attempt to modify read-only table") end, }) else return nil end end 
0
source

All Articles