Lua Sandbox具有泄漏的特殊功能

时间:2011-10-22 02:49:03

标签: lua sandbox

我正在尝试使用How can I create a secure Lua sandbox?构建我自己的漏洞沙箱。

我正在尝试创建一个Lua沙箱,其中一些Lua函数可以访问沙箱外的其他一些Lua函数。例如,我希望我的沙箱有一个特殊的“显示”功能,可以调用“打印”但在沙箱中也没有“打印”。

主要问题是我正在尝试在已经很大的代码库中构建一个沙箱,所以我不能忽略功能。

这怎么可能?

由于没有我的错误,解决方案必须是纯粹的Lua函数。

3 个答案:

答案 0 :(得分:5)

创建沙箱时,可以通过从较大的环境中挑选函数和值来创建新的沙箱环境。你不需要在原始环境中销毁或“清除”任何东西。

  1. 通过樱桃挑选功能和值创建沙盒环境
  2. 加载脚本(将其编译并将其作为要调用的函数返回)
  3. 将脚本环境设置为沙盒环境
  4. 执行沙箱中的脚本
  5. 所以,

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

    打印

    0.69314718055995
    

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

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

答案 1 :(得分:1)

是否需要调用Lua标准库print函数?您可以改为模仿print的功能吗?因为这是最简单的方法。

但是,如果你想拥有print的包装器,有两种方法可以做到:使用纯Lua代码和C / C ++代码。

纯Lua溶液如下。请注意,这应该在加载任何外部脚本之前完成。首先,打开其中包含print的Lua标准库。然后运行这个Lua脚本:

local internal_print = print

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

这将返回“显示”功能。如果您愿意,可以将其存储在名为display的全局变量中,或者调用其他内容。

之后,您可以nil print全局变量,从而使其几乎完全无法访问。

如果你想用C / C ++来做,那就非常相似了。首先,和以前一样,您注册包含print的Lua标准库,以便您可以获得它的功能。然后,使用lua_getglobal(L, "print")获取print函数并将其推入堆栈。接下来,使用lua_pushcclosure注册C / C ++函数。但是你想指定一个upvalue,Lua会在注册时弹出堆栈。

现在你的注册函数在堆栈中,等待被推入Lua变量或全局表项。

警告: Lua调试库可以查看upvalues,从而从新函数中获取print函数。因此,如果您想要完美的安全性,请摆脱debug.getupvalue

答案 2 :(得分:0)

构建沙箱(或多个沙箱,如果它们各自有不同的要求),并将不受信任的代码一次一个地移动到沙箱中。在我的快速cli测试中,5.1和5.2都将运行在沙箱之外定义的函数而不进行修改。要使用Doug的示例,假设display是使用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

请注意,在上述两个示例中,display函数正在使用print而不修改该代码,因为在创建此函数时您不在沙箱中。

在过去,我已经存储了一个指向非沙盒环境的本地指针,但是我无法重现我在快速cli测试中需要的情况。如果你能想出一个例子,我可能会想出一个不需要e变量的解决方法。以下是使用5.2的代码示例:

local e=_ENV

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

另一个例子,对于我的只读表格代码,我再次使用e

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