【问题标题】:UNIX ptrace() block child's system callsUNIX ptrace() 阻止子系统调用
【发布时间】:2011-06-09 22:57:45
【问题描述】:

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

【问题讨论】:

    标签: linux unix ptrace


    【解决方案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)
    

    生成文件:

    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机制'吗?
    • 如果您将 $LD_PRELOAD 环境变量设置为指向共享库,那么将优先使用该库而不是可执行文件中设置的库。我不知道它是否适用于系统级功能。
    • 好的,那么第二个选项:我需要在setrlimit()中设置什么资源来阻止系统调用?
    • RLIMIT_NPROC。我目前正在实施第一个选项的测试版本,但到目前为止看起来并不好。我会用结果更新我的答案。
    • 请注意,LD_PRELOAD 不会阻止程序进行直接系统调用,例如通过int 0x80。它不是作为一种安全措施而设计的。
    【解决方案2】:

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

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

    如果您只针对 Linux,我建议您改为使用 seccomp,这是一种更快的技术,可将某些系统调用列入白名单/黑名单或限制其参数。

    另一种选择是 Google 的 Native Client。 该项目提供了应用沙箱的跨平台实现。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-23
      • 2012-08-14
      • 1970-01-01
      • 2011-07-26
      • 2013-09-08
      • 2017-01-03
      • 2012-04-03
      • 1970-01-01
      相关资源
      最近更新 更多