我想知道是否存在在Linux下的沙箱下运行不受信任的C程序的方法.什么会阻止程序打开文件,网络连接,分叉,执行等?
它将是一个小程序,一个家庭作业,它被上传到服务器并在其上执行单元测试.所以该计划将是短暂的.
我已经使用Systrace以交互方式和自动模式对不受信任的程序进行沙盒化.它有一个ptrace()
基于后端,允许在没有特殊权限的Linux系统上使用它,以及需要修补内核的更快,更强大的后端.
也可以在类Unix系统上使用创建沙箱chroot(1)
,尽管这不是那么容易或安全.Linux Containers和FreeBSD jails是chroot的更好选择.Linux上的另一个替代方案是使用像SELinux或AppArmor这样的安全框架,这是我为生产系统提出的建议.
如果您告诉我们您想要做什么,我们将能够为您提供更多帮助.
编辑:
Systrace适用于您的情况,但我认为基于Linux安全模型(如AppArmor或SELinux)的内容是一种更标准的,因此更受欢迎的选择,具体取决于您的发行版.
编辑2:
虽然chroot(1)
大多数(所有?)类Unix系统都可用,但它有很多问题:
它可以打破.如果要在系统上实际编译或运行不受信任的C程序,则特别容易受到此问题的影响.如果你的学生和我一样,有人会试图突破监狱.
您必须创建一个完整的独立文件系统层次结构,其中包含您的任务所需的所有内容.您不必在chroot中有编译器,但应包含运行编译程序所需的任何内容.虽然有一些实用程序可以帮助解决这个问题,但它仍然不是一件容易的事.
你必须保持chroot.由于它是独立的,因此chroot文件不会随您的发行版一起更新.您将不得不定期重新创建chroot,或者在其中包含必要的更新工具,这实际上要求它是一个完整的Linux发行版.您还必须保持与主机系统同步的系统和用户数据(密码,输入文件等).
chroot()
只保护文件系统.它不会阻止恶意程序打开网络套接字或者写得不好的程序来吸收所有可用资源.
资源使用问题在所有备选方案中都很常见.文件系统配额将阻止程序填充磁盘.正确的ulimit
(setrlimit()
在C中)设置可以防止内存过度使用和任何叉式炸弹,以及阻止CPU占用.nice(1)
可以降低这些程序的优先级,以便计算机可以用于任何被认为更重要而没有问题的任务.
我最近写了一篇关于Linux中沙盒技术的概述.我认为你最简单的方法是使用Linux容器(lxc),如果你不介意分叉等等,这在这个环境中并不重要.您可以为进程提供只读的根文件系统,隔离的环回网络连接,您仍然可以轻松地终止它并设置内存限制等.
Seccomp会有点困难,因为代码甚至无法分配内存.
Selinux是另一种选择,但我认为它可能比容器更多的工作.
您可以使用Qemu快速测试作业.在我5岁的笔记本电脑上,此程序不到5秒钟.
让我们假设学生必须开发一个程序,该程序采用无符号整数,每个都在自己的行上,直到一行"-1"到达.然后程序应平均所有整数并输出"Average:%f".以下是测试程序完全隔离的方法:
首先,root.bin
从Jslinux 获取,我们将使用它作为userland(它具有tcc C编译器):
wget https://github.com/levskaya/jslinux-deobfuscated/raw/master/root.bin
我们想把学生的提交放入root.bin
,所以设置循环设备:
sudo losetup /dev/loop0 root.bin
(你也可以使用fuseext2,但它不是很稳定.如果它稳定了,你不需要任何root用户)
制作一个空目录:
mkdir mountpoint
装载root.bin
:
sudo mount /dev/loop0 mountpoint
输入挂载的文件系统:
cd mountpoint
.
修复权利:
sudo chown -R `whoami` .
mkdir -p etc/init.d
vi etc/init.d
:
#!/bin/sh cd /root echo READY 2>&1 > /dev/ttyS0 tcc assignment.c 2>&1 > /dev/ttyS0 ./a.out 2>&1 > /dev/ttyS0
chmod +x etc/init.d/rcS
将提交复制到VM:
cp ~/student_assignment.c root/assignment.c
退出VM的根FS:
cd ..
sudo umount mountpoint
现在图像准备就绪,我们只需要运行它.它将在引导后编译并运行提交.
mkfifo /tmp/guest_output
打开一个单独的终端并开始侦听来宾输出:
dd if=/tmp/guest_output bs=1
在另一个终端:
qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput
(我刚才在这里使用了Ubuntu内核,但很多内核都可以使用)
当guest虚拟机输出显示"READY"时,您可以从qemu提示符向VM发送密钥.例如,要测试此分配,您可以这样做
(qemu) sendkey 1 (qemu) sendkey 4 (qemu) sendkey ret (qemu) sendkey 1 (qemu) sendkey 0 (qemu) sendkey ret (qemu) sendkey minus (qemu) sendkey 1 (qemu) sendkey ret
现在Average = 12.000000
应该出现在guest输出管道上.如果没有,那么学生就失败了.
退出qemu: quit
通过测试的程序在这里:https://stackoverflow.com/a/14424295/309483.只需使用tcclib.h
而不是stdio.h
.
尝试用户模式Linux.对于CPU密集型作业,它的性能开销约为1%,但对于I/O密集型作业,它可能会慢6倍.