静态与动态链接沙盒
我在我的项目中尝试使用 libsandbox。我可以在这个沙盒里完美地运行 C/C++ 程序。
为了运行 C/C++ 程序,首先我需要将代码编译成:
g++ -lm --static <filename> 2> err.txt
然后,我需要用上面编译好的代码运行 示例沙盒程序。
请注意,我上面使用的标志 --static 是非常重要的。这个 --static 的重要性在以下两个 StackOverflow 的回答中体现得很清楚 链接1, 链接2。
现在,我想把这个沙盒也用在 Java 和 Python 上。
但是我不知道 Python 和 Java 中与 gcc/g++ --static 相对应的选项是什么。
下面的代码能行吗?
javac --static <filename> 2> err.txt
python --static <filename> 2>err.txt
我再说一遍,我很困惑,因为我不知道 Java 或 Python 中 --static 的对应选项。
谢谢!
3 个回答
对于Java来说,似乎你唯一的选择就是使用一个叫做JNI的包装器,它是静态绑定的。可能已经有这样的包装器了,但如果没有的话,你可以自己写一个。
我觉得你把两件事情搞混了。你的Python程序并不是libsandbox
所说的可执行文件。可执行文件是Python解释器。
所以,你不能用libsandbox
来对一个Python脚本进行沙箱处理。
不过,你可以对Python解释器进行沙箱处理。你可以用和处理其他可执行文件相同的方法来做到这一点。具体来说,有两种方式:
- 创建一个静态构建的Python解释器(把你需要的C扩展模块编译进去),然后在沙箱中运行它。这并不简单,但可以做到,Python源代码中和其他地方有一些信息可以帮助你。
- 使用一个更宽松的沙箱,允许标准解释器做它需要做的事情(这可能包括动态加载扩展模块,具体取决于你是否需要这样做),但不允许其他的。
无论哪种方式,你都需要一些试验和错误来弄清楚哪些操作可以禁止,哪些不可以,以及如何将不同的Python代码映射到系统调用等等。而且,有些事情你是无法阻止你的脚本去做的,因为你不希望Python代码执行的系统调用对于解释器本身是必要的。
Java也是类似的情况。JVM是可执行文件,而不是你的程序。而且你真的不能静态链接JVM,所以你只能选择第二种方式。
当然,除非你使用gcj
将你的Java代码编译成本地代码,而不是JVM代码。在这种情况下,你实际上使用的是和gcc
和g++
相同的后端,只需使用--static
确保libgcj
和其他所有内容都被静态链接。你可能仍然会遇到问题,因为libgcj
在背后做的事情比libc
多得多……但这个概念和C代码是一样的。
(JVM本身有自己的访问模型,你可以假设使用反射在类加载器中构建一些东西,以在Java API的层面上对Java程序进行沙箱处理,而不是Linux系统调用API。我不知道是否已经存在这样的东西。)
每当我尝试编译我想在沙箱中运行的程序时,如果不加“--static”,沙箱就无法工作。所以,再次强调,--static是非常关键的,这超出了我的知识范围。
很可能,你的实际代码并没有打开任何文件,所以你使用的是默认的沙箱设置,这禁止打开文件。但是如果你动态链接你的程序,它就必须打开.so
文件来进行链接——这就不行,因为你的沙箱配置是禁止这样做的。
如果你静态链接同样的程序,这个问题就解决了,因为它不再需要打开任何.so
文件来运行。简单来说,这就是静态链接在沙箱处理中的意义。你甚至在你问题的评论中解释过这一点,所以我无法想象你怎么会不理解,除非你根本不明白为什么要禁止SYS_open
以及这样做的意义。
(a) 对于Java和Python,如果我不加“--static”编译,沙箱会有效吗?
是的,沙箱会正常工作。这意味着,如果你使用默认配置,它会禁止你打开文件。这意味着你的Java或Python程序会失败,因为虚拟机/解释器必须打开(除了其他事情)你的程序来运行它。
即使静态链接解释器或JVM也无济于事。你必须将你的程序的实际字节码静态链接到可执行文件中。这并不是不可能,但可能超出了你现在想要考虑的范围。
正确的做法是弄清楚你想禁止哪些系统调用,以及为什么要禁止它们,并相应地配置沙箱。默认配置对你来说是行不通的。
(b) 有一个叫做pysandbox的沙箱,由同一个开发者提供,地址是openjudge.net/~liuyu/Project/LibSandbox
pysandbox
只是一个更简单的配置和启动沙箱的方法。你不会在沙箱代码内部使用它。(还有一个由其他开发者提供的pysandbox
,它在Python层面上对你的代码进行沙箱处理。这可能对你有用,但与系统调用沙箱不是同一回事。)
在这一点上,我不确定你是否知道自己在做什么。你为什么想要对你的代码进行沙箱处理?你知道你的代码需要什么样的访问权限才能完成它需要做的事情吗?如果你知道自己在做什么,你确定系统调用级别的沙箱是强制执行的正确层面,而不是像RestrictedPython
这样的东西吗?如果不知道你的实际使用案例,我甚至无法猜测这些问题的答案。但是如果你对这些问题没有立即的答案,你就无法完成任何有用的事情。
可以使用 libsandbox
来对 Python 解释器进行沙箱处理。沙箱处理就是限制程序的权限,让它不能随便做一些事情,比如加载共享库和导入默认的 Python 模块。你可以在 Richard Lobb 的 CodeRunner
项目中找到一个在 Python3 解释器上运行的示例。
https://github.com/trampgeek/CodeRunner
Java 自己有安全机制,所以不需要把 Java 虚拟机放在沙箱里。
免责声明:我是 libsandbox
的作者。