c - seccomp:从 parent 那里,找到哪个系统调用导致 child 在 SIGSYS 上死亡

标签 c linux signals seccomp

我会详细描述我的问题,请原谅我的不守规矩和粗暴。

我做过一些关于 seccomp-BPF 和信号处理的实验。一开始我跟着这个tutorial .

添加 SIGSYS 信号处理(syscall-reporter.c)后,如果程序执行一些无效的系统调用,我可以在下面得到一些输出:

Looks like you need syscall fstat(5) too!

我想知道如果我使用 execve 函数或其他方法执行任何其他可执行文件,如何打印系统调用名称。

我试过这样的事情:主进程(刚刚命名为P0的进程)首先添加SIGCHLD信号处理,并派生一个子进程(名为P1)。 P1 将添加 seccomp-bpf 规则并对无效系统调用执行 seccomp 操作 SCMP_ACT_TRAP,然后使用 execve 函数将 P1 替换为可执行文件(名为 E)。当执行E调用一些无效的系统调用时,P1会抛出SIGSYS信号退出,然后向P0发送SIGHLD信号。似乎 P0 在收到 SIGHLD 信号后无法从 ucontext_t 中获取无效的系统调用名称。

P1本身不能打印系统调用名是因为

during an execve(2),the dispositions of handled ignals are reset to the default;

(来自 sigaction man-pages)

抱歉我的英语不好。

最佳答案

我在使用 libseccomp 时遇到了完全相同的问题对通过 fork + execvp 启动的进程进行沙盒处理。

我的解决方案涉及对子进程执行 ptrace。本质上,这个想法是跟踪子进程并检查它接收到的每个信号。在被跟踪时,收到的每个信号都会导致子进程陷入陷阱,我们可以在父进程的 SIGCHLD sigaction 处理程序中检测到这一点 (si_code == CLD_TRAPPED)。

当子进程接收到的信号是 SIGSYS 时,由 seccomp 系统调用的 SECCOMP_RET_TRAP 操作触发,我们在 中获得有问题的系统调用号siginfo_t 的 si_syscall 成员。为了获取有问题的系统调用的名称,我使用了 libseccomp 的解析器,但您可以使用任何其他方法。

具体来说,在 fork 之后和 execvp 之前,子进程调用:

ptrace(PTRACE_TRACEME, 0, NULL, NULL);

然后,在父进程的 SIGCHLD sigaction 处理程序中:

#include <seccomp.h>
#include <signal.h>
#include <sys/ptrace.h>

#ifndef SYS_SECCOMP
#define SYS_SECCOMP 1
#endif

void sigchld_sigaction(int sig, siginfo_t *info, void *ucontext) {
    if(info->si_code == CLD_TRAPPED) {
        siginfo_t cinfo;
        ptrace(PTRACE_GETSIGINFO, info->si_pid, NULL, &cinfo);
        if(cinfo.si_code == SYS_SECCOMP && cinfo.si_signo == SIGSYS) {
            char *sc_name = seccomp_syscall_resolve_num_arch(cinfo.si_arch,
                                                             cinfo.si_syscall);
            fprintf(stderr, "Looks like you need syscall %s(%d) too!\n",
                    sc_name, cinfo.si_syscall);
            free(sc_name);
            exit(EXIT_FAILURE);
        }
        ptrace(PTRACE_CONT, info->si_pid, NULL, NULL);
    }
}

关于c - seccomp:从 parent 那里,找到哪个系统调用导致 child 在 SIGSYS 上死亡,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53104444/

相关文章:

c++ - GTK 应用程序 : How do I create a working indicator with Qt/C++?

linux - 如何使用 QEMU 调试 Linux 内核模块?

c - 为 Linux 内核开发设置 Netbeans/Eclipse

cuda:如何将主机数据复制到 3D cuda 数组并返回

无法安装 MySQL 服务器

java native loadlibrary 无法加载库 - Linux fedora25 java8

Linux PTY 作为模块,但没有信号

linux - 如果终端突然关闭或终端失去网络连接,如何处理 shell 脚本?

linux - mongoDB (result= signal , code = killed , signal = ill

c - 在哪里用 gcc 设置了 c 函数属性(如何取消设置)