嵌入式Lua - 超时处理恶意脚本(例如无限循环)- 能举个例子吗?

我已经在 C++ 应用程序中嵌入了 Lua。 我需要能够杀死恶意编写的脚本,以免占用资源。

我知道我无法为导致脚本无限运行的每种类型的条件提供服务,因此,目前,我只关注简单的 Lua 方面(即脚本方面的问题)。

我也知道这个问题已经在 Stack Overflow 上以各种形式被问过。可能被反复提问的原因是因为迄今为止,还没有人提供几行代码来显示如何在工作代码中实际实现超时(对于像我上面描述的简单情况),而不是谈论关于如何实现它的概括。

如果任何人都在嵌入 Lua 应用程序的 C++ 中实际实现了这种功能,我(以及许多其他人-我相信)将非常感激一小段代码片段,其中显示:

  • 在运行 Lua 脚本之前如何设置超时(在 C++ 方面)
  • 如何引发超时事件/错误(C++ / Lua?)
  • 如何处理错误事件/异常(C++ 方面)

这样的代码片段(即使是伪代码)确实非常有用。

原文链接 https://stackoverflow.com/questions/5134287

点赞
stackoverflow用户1491
stackoverflow用户1491

Snippet 这个术语并不适用于实现这个功能,因此你可能没有看到这个东西。你可以使用调试钩子来提供 Lua 代码执行期间的回调。然而,在超时后打断该过程是具有一定难度的,这取决于您特定的架构。

您可以考虑在捕获到 luaHook 中的超时后,在调用 lua_calllua_pcall 之前使用 longjmp 到跳转缓冲区中。然后,关闭该 Lua 上下文并处理异常。超时可以通过多种方式实现,您可能已经在项目中的其他地方使用了某些方法。

完成此任务的最佳方法是在单独的进程中运行解释器。然后使用提供的操作系统工具来控制子进程。请参考 RBerteig 的出色回答以获取有关该方法的更多信息。

2011-02-28 06:25:35
stackoverflow用户68204
stackoverflow用户68204

你需要使用多种技术来解决这个问题。首先,你需要建立一个适当的沙盒来运行不可信脚本,提供的环境应该只包含安全和必需的全局变量和函数。其次,你需要限制内存和 CPU 的使用。第三,你需要明确拒绝从不可信来源加载预编译的字节码。

第一个问题很容易解决。Lua 用户维基、邮件列表和这里的 SO 上都有关于 Lua 沙盒的讨论。如果你意识到某些脚本比其他脚本更可信,那么你几乎肯定已经在做这部分了。

第二个问题是你正在问的。我马上回来讨论这个问题。

第三个问题已在邮件列表上讨论过,但在其他媒体上可能没有表述得很清楚。现在已经发现,有许多在 Lua 核心中很难或无法解决的漏洞,但是这些漏洞取决于“错误”的字节码。也就是说,它们无法从 Lua 源代码中操作,只能从预编译的、经过仔细修补的字节码中操作。编写一个加载程序以拒绝加载任何二进制字节码是很简单的。

有了这些点的解决方法,剩下的问题就是拒绝服务攻击,包括 CPU 和内存的消耗。首先,不好的消息。没有完美的技术可以防止这种攻击。但是,其中最可靠的方法之一是将 Lua 解释器推入单独的进程中,使用平台的安全和配额功能来限制该进程的能力。在最坏的情况下,失控的进程可以被终止,对主要应用程序没有任何伤害。这种技术被最新版本的 Firefox 用于包含插件中的 bug 的副作用,所以这并不像听起来那么疯狂。

一个有趣的完整例子是 Lua Live Demo。这是一个网页,你可以输入 Lua 代码样例,在服务器上执行并查看结果。由于脚本可以匿名从任何地方输入,它们显然是不可信的。这个 Web 应用程序似乎是可以要求的最安全的。它的源代码包可以从 Lua 的一位作者的网站上下载。

2011-02-28 07:12:16
stackoverflow用户147749
stackoverflow用户147749

一个非常天真和简单的方法(但全部为 Lua 编写)是:

-- 根据您的需求,限制可能在百万级别
setfenv(code,sandbox)
pcall(function()
  debug.sethook(function()
    error("Timeout!")
  end, "", limit)
  code()
  debug.sethook()
end)

我认为你也可以通过使用 C API 来实现相同的功能。

然而,这种方法有许多问题。将限制设置得太低,它不能完成它的工作;将限制设置得太高,它也不是非常有效(代码块可以反复运行吗?);如果允许代码调用阻塞一段时间的函数,则以上所述内容是毫无意义的;同时,如果允许它做任何类型的 pcall,那么它可以自行陷入错误。我还没有考虑到的任何其他问题。而且我正在忽略有关对 debug 库(除了调试之外)使用的警告。

因此,如果您想使它更可靠,最好使用 RB 的解决方案。

我认为,对于「意外」的无限循环,即刚开始学习 Lua 的程序员经常喜欢的那种类型,它应该可以发挥出相当好的效果。

对于过度使用内存,您可以使用一个检查 collectgarbage("count") 增加的函数,在更小的间隔内检查;您需要将它们合并在一起才能获取两者的信息。

2011-03-19 00:10:35