【问题标题】:Getting "Bad System Call" working with seccomp filters使用 seccomp 过滤器获取“错误系统调用”
【发布时间】:2021-08-27 05:07:12
【问题描述】:

我刚刚开始学习 seccomp 过滤器,我正在使用 libseccomp v2.4.4。我尝试编写一个基本的白名单过滤器,它只允许写入名为file1 的文件,但我在STDOUT 中收到“错误的系统调用”消息。这是我的代码:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <seccomp.h>
#include <stdlib.h>
#include <errno.h>

int main(void)
{
        FILE *fil = fopen("file1", "w");
        scmp_filter_ctx filter = seccomp_init(SCMP_ACT_KILL);

        if (filter==NULL || NULL==fil)
                goto End1;

        int chk1 = seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(write), 1,
                                    SCMP_A0(SCMP_CMP_EQ, fileno(fil)));
        int chk2 = seccomp_load(filter);
        if (chk1<0 || chk2<0)
                goto End;

        fprintf(stdout,"Filter did not work correctly\n");
        fprintf(fil,"Filter worked correctly\n");

End:
        seccomp_release(filter); //releasing filter before closing file
        fclose(fil);

End1:
        return 0;
}

此外,我在file1 中看不到任何输出。我只是一个初学者,对这里的很多事情都不确定,因为我是根据自己的理解编写代码,而不是参考一些参考资料。似乎是什么问题?


编辑:我完全删除了过滤器并简单地执行了

int main(void)
{
        FILE *fil = fopen("file1", "w");

        fprintf(stdout,"Filter did not work correctly\n");
        fprintf(fil,"Filter worked correctly\n");

End:
        fclose(fil);

End1:
        return 0;
}

跟踪这一点,我观察到系统调用 fstat,close 在@pchaigno 下面的答案中提到,另外mmap,munmap 正在被调用。所以我必须允许这些系统调用来实现预期的行为。

【问题讨论】:

    标签: c linux runtime-error bpf seccomp


    【解决方案1】:

    调试

    跟踪您的应用程序会发现问题:

    $ strace ./test
    [...]
    seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=12, filter=0x55ace60a6600}) = 0
    fstat(1,  <unfinished ...>)             = ?
    +++ killed by SIGSYS (core dumped) +++
    Bad system call (core dumped)
    

    允许最少的系统调用集

    您需要允许更多的系统调用,而不仅仅是write(2),以便程序结束时继续进行而不会出错。

    您需要fstat(2) 用于fprintf()close(2) 用于fclose()exit_group(2) 以结束该过程。

    拒绝系统调用而不是杀死进程

    此外,如果您希望程序在未经授权的系统调用后继续运行,则不应使用SCMP_ACT_KILL 将其终止。 SCMP_ACT_ERRNO(EPERM) 在这种情况下可能更合适。

    结果

    int main(void) {
            FILE *fil = fopen("file1", "w");
            scmp_filter_ctx filter = seccomp_init(SCMP_ACT_ERRNO(EPERM));
            if (filter == NULL || NULL == fil)
                    return 1;
            if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(write), 1, SCMP_A0(SCMP_CMP_EQ,fileno(fil))) < 0)
                    goto err;
            if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0) < 0)
                    goto err;
            if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(close), 0) < 0)
                    goto err;
            if (seccomp_rule_add(filter, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0) < 0)
                    goto err;
            if (seccomp_load(filter) < 0)
                    goto err;
            fprintf(stdout, "Filter did not work correctly\n");
            fprintf(fil, "Filter worked correctly\n");
    err:
            seccomp_release(filter); //releasing filter before closing file
            fclose(fil);
            return 0;
    }
    

    给我们:

    $ ./test; echo file1
    Filter worked correctly
    

    【讨论】:

    • 感谢您的精彩回答。我有一些后续问题:1.我们是否需要允许fstat syscall,允许write syscall 是否不启用fprintf?程序在不允许fstat 的情况下正确执行。 2. 我们需要允许close 系统调用吗?我在释放过滤器后使用fclose 语句。我试图在关闭语句之后写入fil,而不允许close 系统调用,它出现了分段错误,表明文件关闭。看起来程序运行正常,只需添加exit_group
    • 我不确定fstat(2),但请注意,即使程序没有错误地退出,这并不意味着它的行为符合预期。例如,在fclose 的情况下,您不能再写入fil 的事实并不意味着文件描述符被内核视为关闭。您可能仍在泄漏文件描述符。另外,当fstat(2) 被seccomp 拒绝时,您是否检查fprintf 返回零错误代码?
    • 您好,感谢您的回复。我删除了 seccomp 过滤器并跟踪了仅包含打开文件、写入文件和标准输出然后关闭文件的操作的程序。事实证明,确实有人打电话给fstatclosemmap。所以我必须允许这些系统调用从我的过滤器中获得预期的行为。谢谢你把我介绍给strace
    猜你喜欢
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-21
    • 2020-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多