如何从C API中在Lua文件的独立环境中执行一个不可信的Lua文件。
我想通过调用 lua_setfenv() 在单独的环境中执行一个不可信的 .lua 文件,以便它不会影响我的任何代码。
不过,该功能的文档仅解释了如何调用函数,而没有解释如何执行文件。
目前,我使用以下代码运行文件:
int error = luaL_loadfile(mState, path.c_str()) || lua_pcall(mState, 0, 0, 0);
我是否需要使用 lua_setfenv
从 C API 调用 "dofile" lua 函数,或者是否有更优雅的方法?
原文链接 https://stackoverflow.com/questions/3444312
请参阅 Lua 用户 Wiki 上有关沙箱技术(sandboxing)的讨论,以及更一般的脚本安全(script security)主题。这种技术涉及到一些微妙或不太微妙的问题。它可以实现,但是保护自己不受 for i=1,1e39 do end
等代码的威胁需要不仅仅是限制沙箱可以使用哪些函数。
通常的技术是在沙箱中创建一个函数环境,其中包含了允许使用的函数白名单。在某些情况下,列表甚至可能为空,但是让用户可以访问 pairs()
这样的函数几乎肯定是无害的。沙箱页面上列出了系统函数按安全性分解的列表,可以作为构建白名单的便捷参考。
然后使用 lua_setfenv()
将函数环境应用到用户脚本上,该脚本是使用适当的 lua_loadfile()
或 lua_loadstring()
加载的(但尚未执行)。在附加环境之前,一些人实际上已经扫描了加载的字节码,以查找不想允许的操作。这可以用来绝对禁止循环或写入全局变量。
另一个注意事项是加载函数通常会加载预编译的字节码或 Lua 文本。如果你从未允许过预编译的字节码会更加安全,因为已经发现了许多使虚拟机(VM)发生异常的方式,这些方式都依赖于手工制作的无效字节码。由于字节码文件以非普通 ASCII 文本开始,因此你只需要将脚本读入字符串缓冲区中,检测标记的短缺,并且仅在不是字节码时将其传递给 lua_loadstring()
。
多年来,Lua-L 邮件列表上也就此类问题进行了相当多的讨论,因此在那里搜索也可能是有帮助的。
顺便说一下,这是我最终所做的:
/* 加载、编译并执行一个不受信任的文件 */
bool Lua::RunUntrustedFile(const string& path)
{
if(luaL_loadfile(mState, path.c_str()))
{
ErrorLog(lua_tostring(mState, 1));
Pop(1);
return false;
}
Lua::SetMaximumInstructions(100000000);
lua_newtable(mState);
lua_setglobal(mState, "upload");
ASSERT(Lua::GetStackSize() == 1);
lua_getglobal(mState, "upload");
ASSERT_ALWAYS(lua_setfenv(mState, 1) != 0);
ASSERT(Lua::GetStackSize() == 1);
if(lua_pcall(mState, 0, 0, 0))
{
Lua::ClearMaximumInstructions();
ErrorLog(lua_tostring(mState, -1));
Pop(1);
return false;
}
ASSERT(Lua::GetStackSize() == 0);
Lua::ClearMaximumInstructions();
return true;
}
“支持”函数:
static void Pop(int elements = 1) { lua_pop(mState, elements); }
/* 设置一个最大指令数,超过此数即抛出错误 */
static void SetMaximumInstructions(int count) {
lua_sethook(mState, &Lua::MaximumInstructionsReached, LUA_MASKCOUNT, count);
}
static void ClearMaximumInstructions() {
lua_sethook(mState, &Lua::MaximumInstructionsReached, 0, 0);
}
static void MaximumInstructionsReached(lua_State *, lua_Debug *)
{
Error("已达到最大指令数");
}
static int GetStackSize() { return lua_gettop(mState); }
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
luaL_loadfile()
函数会加载代码块,然后调用lua_setfenv()
设置环境表,最后调用lua_pcall()
执行代码块。请参考 Judge Maygarden 在 Calling lua functions from .lua's using handles? 中给出的最新答案。