Lua沙箱具有特殊的泄漏功能
我正试图用它来建造我自己的漏水沙箱 我试图创建一个Lua沙盒,其中一些Lua函数可以访问沙盒之外的其他Lua函数。例如,我希望我的沙盒有一个特殊的“显示”功能,可以调用“打印”,但沙盒中没有“打印” 主要的问题是,我试图在一个已经很大的代码库中构建一个沙盒,因此我无法消除函数 这怎么可能Lua沙箱具有特殊的泄漏功能,lua,sandbox,Lua,Sandbox,我正试图用它来建造我自己的漏水沙箱 我试图创建一个Lua沙盒,其中一些Lua函数可以访问沙盒之外的其他Lua函数。例如,我希望我的沙盒有一个特殊的“显示”功能,可以调用“打印”,但沙盒中没有“打印” 主要的问题是,我试图在一个已经很大的代码库中构建一个沙盒,因此我无法消除函数 这怎么可能 由于没有我的错误,解决方案必须是纯Lua函数。它是否特别需要调用Lua标准库print函数?您是否可以模拟打印的功能?因为那是最简单的方法 但是,如果您想在print周围有一个包装器,有两种方法可以做到这一点:
由于没有我的错误,解决方案必须是纯Lua函数。它是否特别需要调用Lua标准库
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\u getglobal(L,“print”)
获取print
函数并将其推到堆栈上。接下来,使用lua\u pushcclosure
注册C/C++函数。但是您希望指定一个upvalue,Lua在注册时从堆栈中弹出该值
现在,您注册的函数位于堆栈上,等待被推送到Lua变量或全局表条目中
警告:Lua调试库可以戳取upvalues,从而从新函数中获取
print
函数。因此,如果您希望获得完美的安全性,那么在创建沙盒时,可以通过从更大的环境中选取函数和值来创建新的沙盒环境,从而摆脱debug.getupvalue
。您不需要在原始环境中销毁或“取消”任何内容
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)
构建您的沙盒(或者多个沙盒,如果每个沙盒有不同的需求),并将不受信任的代码一次一个地移动到沙盒中。在我的quick cli测试中,5.1和5.2都将运行在沙箱外部定义的函数,而无需修改。要使用Doug的示例,假设display
是使用print
的现有代码的一部分:
--5.1
本地功能显示(…)
打印(…)
结束
本地脚本=loadstring“显示(math.log(2,3))”
本地环境={display=display,math=math,string=string}
塞特芬夫(脚本,环境)
打印(pcall(脚本))
-- 5.2
本地功能显示(…)
打印(…)
结束
本地脚本=loadstring“显示(math.log(2,3))”
本地环境=_环境
_ENV={display=display,math=math,string=string}
e、 打印(e.pcall(脚本))
_环境=e
请注意,在上述两个示例中,display
函数正在使用print
,而不修改该代码,因为创建该函数时您不在沙箱中
在过去,我存储了一个指向非沙盒环境的本地指针,但我无法重现quick 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
“印刷品”只是一个简单的例子来解释这个概念。此外,我不能取消旧的“打印”,因为有大量的代码可以直接访问它。这似乎接近我想要的。我会试试看它是否能按我需要的方式工作。
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