UNIX ptrace()如何阻止子进程的系统调用?

3

我正在开发一个编程竞赛的评分器。基本上,评分器必须在一个“隔离”的进程中运行解决方案程序。因此,我希望解决方案不调用任何有害的系统调用(例如system(),fork()等)。我可以使用ptrace()来实现吗?

2个回答

1

我认为有两种可能的解决方案:

  1. 使用LD_PRELOAD机制创建“shim”来替换您想要停止的系统调用。
  2. 使用setrlimit()限制调用进程可以执行的操作。不幸的是,这些限制似乎是基于每个用户而不是每个进程的基础,这使得计算正确值变得非常困难。

编辑:我已经让第一个选项起作用,并在下面包含了必要的代码。使用make all构建二进制文件,然后使用make runtests进行测试:

$ make all
gcc -fPIC -shared -Wl,-soname,libmy.so.1 -o libmy.so.1.0 lib.c
ln -sf libmy.so.1.0 libmy.so.1
ln -sf libmy.so.1 libmy.so
gcc -o test test.c

$ make runtests
Without LD_PRELOAD:
./test
in child: retval=9273
in parent: retval=0
With LD_PRELOAD:
LD_PRELOAD=./libmy.so ./test
libmy.so fork!
fork error: error=Operation not permitted (1)

Makefile:

all: libs test

runtests:
    @echo Without LD_PRELOAD:
    ./test
    @echo With LD_PRELOAD:
    LD_PRELOAD=./libmy.so ./test


libs: lib.c
    gcc -fPIC -shared -Wl,-soname,libmy.so.1 -o libmy.so.1.0 lib.c
    ln -sf libmy.so.1.0 libmy.so.1
    ln -sf libmy.so.1 libmy.so

test: test.c
    gcc -o test test.c

clean:
    rm -f test libmy.so.1.0 libmy.so.1 libmy.so lib.o

lib.c:

#include <stdio.h>
#include <unistd.h>
#include <errno.h>

pid_t fork()
{
    printf("libmy.so fork!\n");
    errno = EPERM;
    return (pid_t)-1;
}

test.c:

#include <stdio.h>
#include <string.h>
#include <errno.h>

int main(int argc, char **argv)
{
    int retval = fork();
    if (retval == 0)
        printf("in parent: retval=%d\n", retval);
    else if (retval > 0)
        printf("in child: retval=%d\n", retval);
    else
        printf("fork error: error=%s (%d)\n", strerror(errno), errno);
    return 0;
}

谢谢,但您能详细解释一下“LD_PRELOAD机制”吗? - fushar
如果您将$LD_PRELOAD环境变量设置为指向一个共享库,那么该库将优先于可执行文件中设置的库进行使用。不过我不知道它是否适用于系统级函数。 - trojanfoe
好的,那么第二个选项:我需要设置setrlimit()中的哪个资源来防止系统调用? - fushar
RLIMIT_NPROC。我目前正在实现第一个选项的测试版本,但目前看起来效果不佳。我会更新我的答案并公布结果。 - trojanfoe
4
请注意,LD_PRELOAD无法阻止程序通过'int 0x80'等方式进行直接系统调用。它不是作为一种安全措施而设计的。 - jilles
显示剩余3条评论

0

是的,您可以使用ptrace()函数并使用PTRACE_SYSCALL选项来阻止某些系统调用。 这里有一个使用此功能的项目:

https://github.com/t00sh/p-sandbox/blob/master/p-sandbox.c

如果你只针对Linux,我建议使用更快的技术seccomp,来白名单/黑名单某些系统调用或限制它们的参数。

另一种选择是谷歌的Native Client。该项目提供了一个跨平台的应用程序沙盒实现。

您还可以在docker或LXC等容器中以非特权用户身份运行应用程序,以限制损害。

仅使用LD_PRELOAD是不安全的,因为可执行文件可能带有自己的系统调用实现并绕过底层libc。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接