Safe-Runner

根据 fanhq 在北京集训的时候讲的东西,我决定写一个程序,能够“安全”地运行其他程序。

这个程序的主要思想就是利用 ptrace 这个函数。由于用户态的程序不能做任何事,而用户态到内核态需要调用系统函数(简称 syscall 吧), ptrace 支持跟踪一个进程,能够截获每个 syscall 。我们在每次 syscall 的时候检查调用的函数是否合法,例如是否运行了外部程序/读写了外部文件,所以能够相对安全地运行一个程序而不用担心可怕的 rm -rf /

一开始决定用 python 写,安装个 python-ptrace 库觉得差不多了。结果完全不会用啊亲!连猜带蒙 YY 了好久最后还感觉弱爆了,如果程序连续向文件写入 n 个字符,那么需要调用系统函数 read n 次,每调用一次我要检查 read 的参数是否合法(也就是是否打开了不允许打开的文件),如果用 python 来写,那么 IO 效率将惨不忍睹啊。遂决定还是用 C 写吧。

然后准备加入一个功能:卡时/卡空。fanhq 用的是 setrlimit/getrlimit 来限制资源。一旦要超时了,系统会向程序发送一个 SIGXCPU 的信号,然后被 runner 捕获,就可以实现卡时了。但是一个很囧的问题是:setrlimit 限制的是 CPU 时间。如果程序 sleep() 一下……慢慢等去吧。正在为这个感到蛋疼的时候,想起了一个问题——什么程序需要 sleep 啊?我就直接把 nanosleep 这个 syscall B 掉就可以了嘛……

fanhq 在他的程序中给每个 syscall 造了个表,我后来发现 /usr/include/asm/unistd_32.h 这个文件中有个 syscall 的列表,于是直接蒯了= =||

现在另一个很囧的问题是——似乎每个 syscall 我会捕获两遍。是本来就要调用两遍还是我写挂了啊……