gpt4 book ai didi

c - 防止进程在Linux上打开新的文件描述符,但允许通过套接字接收文件描述符

转载 作者:行者123 更新时间:2023-12-02 09:37:25 24 4
gpt4 key购买 nike

我目前在一个项目中,我有一个父进程来设置一个套接字对,派生然后使用此套接字对进行通信。子级如果要打开文件(或其他任何基于文件描述符的资源),则应始终转到父级,请求该资源并获取通过套接字对发送的fd。此外,我想防止 child 自己打开任何文件描述符。

我偶然发现了setrlimit,它成功阻止了子进程打开新的文件描述符,但是它似乎也使通过初始套接字连接发送的任何文件描述符无效。 Linux上是否有任何方法允许单个进程打开任何文件,将其文件描述符发送给其他进程并允许他们使用它们,而又不允许这些其他进程自己打开任何文件描述符?

对于我的用例,可以是任何内核配置,系统调用等,只要可以在fork之后应用,并且可以应用于所有文件描述符(不仅是文件,还可以是套接字,套接字对等)。

最佳答案

您在这里拥有的正是seccomp的用例。

使用seccomp,可以以不同方式过滤系统调用。在这种情况下,您想要做的就是在fork()之后安装一个seccomp过滤器,该过滤器禁止使用open(2)openat(2)socket(2)(以及更多)。
为此,您可以执行以下操作:

  • 首先,使用 seccomp_init(3) 的默认行为SCMP_ACT_ALLOW创建一个seccomp上下文。
  • 然后,使用 seccomp_rule_add(3) 为要拒绝的每个系统调用向上下文添加规则。如果尝试进行系统调用,则可以使用SCMP_ACT_KILL终止进程,使用SCMP_ACT_ERRNO(val)来使系统调用无法返回指定的errno值,或者使用手册页中定义的任何其他action值。
  • 使用 seccomp_load(3) 加载上下文以使其生效。

  • 在继续之前, 请注意,这样的黑名单方法通常比白名单方法更弱。它允许任何未明确禁止的系统调用,并且 可能会导致绕过过滤器。如果您认为要执行的子进程可能是恶意地试图避开过滤器,或者如果您已经知道子进程将需要哪些系统调用,则白名单方法会更好,您应该执行上述相反的操作:使用 SCMP_ACT_KILL的默认操作创建过滤器,并使用 SCMP_ACT_ALLOW允许所需的系统调用。就代码而言,差异很小(白名单可能更长,但步骤相同)。

    这是上述示例(为简单起见,在发生错误的情况下,我正在执行 exit(-1)):
    #include <stdlib.h>
    #include <seccomp.h>

    static void secure(void) {
    int err;
    scmp_filter_ctx ctx;

    int blacklist[] = {
    SCMP_SYS(open),
    SCMP_SYS(openat),
    SCMP_SYS(creat),
    SCMP_SYS(socket),
    SCMP_SYS(open_by_handle_at),
    // ... possibly more ...
    };

    // Create a new seccomp context, allowing every syscall by default.
    ctx = seccomp_init(SCMP_ACT_ALLOW);
    if (ctx == NULL)
    exit(-1);

    /* Now add a filter for each syscall that you want to disallow.
    In this case, we'll use SCMP_ACT_KILL to kill the process if it
    attempts to execute the specified syscall. */

    for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
    err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
    if (err)
    exit(-1);
    }

    // Load the context making it effective.
    err = seccomp_load(ctx);
    if (err)
    exit(-1);
    }

    现在,在您的程序中,您可以调用上述函数在 fork()之后立即应用seccomp过滤器,如下所示:
    child_pid = fork();
    if (child_pid == -1)
    exit(-1);

    if (child_pid == 0) {
    secure();

    // Child code here...

    exit(0);
    } else {
    // Parent code here...
    }

    关于seccomp的一些重要说明:
  • 一旦应用了seccomp过滤器,该进程将无法删除或更改该过滤器。
  • 如果过滤器允许使用fork(2)clone(2),则任何子进程都将受同一过滤器的约束。
  • 如果允许使用execve(2),则在调用execve(2)时将保留现有过滤器。
  • 如果允许prctl(2) syscall,则该进程可以应用其他过滤器。
  • 关于c - 防止进程在Linux上打开新的文件描述符,但允许通过套接字接收文件描述符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59730828/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com