我正在创建一些可以使用任意Groovy代码并执行它的东西(一个IRC bot)。我知道如何使用SecurityManagers对文件访问,线程等进行沙盒访问,但是如果脚本超过128 MB的RAM使用时间或3秒的执行时间(因此没有人让它运行while (true){}
)我想让脚本被杀死。这是我的代码:
private static Object eval(String code) {
GroovyShell sh = new GroovyShell()
return sh.parse(code).run()
}
我真的不想生成一个新的JVM,因为我希望将异常传递给主程序并传递实际对象而不是字符串(如果我打算制作其他前端则重复使用)。
答案 0 :(得分:1)
只需在单独的过程中运行每个脚本。
有几件事要看。第一种方法是将每个脚本放入其自己的classLoader中,该classLoader具有Extensions ClassLoader甚至可能是Bootstrap类加载器作为它的父级。这是为了控制groovy脚本对应用程序类的访问。
监控执行时间很简单。如果超过3秒的限制,只需在其自己的线程和interrupt线程中运行每个脚本。但请记住,中断线程只会引发一个InterruptedException,可以在该线程中捕获和处理。如果代码旨在从那些异常中恢复,那么停止线程并不容易。
记忆部分是事情真正崩溃的地方。 This answer几乎说了所有需要说的 - 不可能。有人可以轻易地让你离开堆空间并使jvm崩溃。
最终,我会真的建议在一个单独的过程中运行每一个。这有很多好处,其中最重要的是,它通过利用将它们作为单独的用户运行来更容易沙箱化。这样,您可以从操作系统获得另一级别的保护。
此外,如果要将异常传递回主java进程,可以非常轻松地完成此操作,因为Exception实现了Serializable。这意味着您可以通过SocketChannel或http,序列化到文件或使用您想要的任何协议轻松地将Exception发送回主进程。有关序列化的一些基本信息,请查看this article。