You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让system()启动的echo子进程继承进程Capabilities权限?

问题背景

我以非root用户运行一个执行echo命令的进程,已通过以下命令为可执行文件设置必要的Capabilities:

setcap cap_net_admin,cap_dac_override,cap_sys_admin=eip test_capab

但由于system()会创建子进程,echo命令并未继承任何权限,导致出现如下错误:

cannot create /proc/sys/net/ipv4/conf/acl_log_all/forwarding: Permission denied
Failed to set /proc/sys/net/ipv4/conf/acl_log_all/forwarding: No such file or directory (errno: 2)

我编写了一个测试程序复现该问题,代码尝试通过Capabilities修改/proc/sys/net/ipv4/conf/acl_log_all/forwarding,但遇到权限问题,测试代码如下:

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/capability.h>

int ipv4_echo2() {
    const char *filepath = "/proc/sys/net/ipv4/conf/acl_log_all/forwarding";
    char buf[256];

    snprintf(buf, sizeof(buf), "echo 1 > %s", filepath);
    if (system(buf) != 0) {
        printf("Failed to set %s: %s (errno: %d)\n", filepath, strerror(errno), errno);
        if (errno == EACCES) {
            printf("Error: Permission denied (EACCES)\n");
        } else if (errno == EPERM) {
            printf("Error: Operation not permitted (EPERM)\n");
        }
        return 1;
    } else {
        printf("Successfully set %s to 1\n", filepath);
    }
    return 0;
}

int main() {
    cap_t caps = cap_get_proc();
    printf("Capabilities: %s\n", cap_to_text(caps, NULL));

    cap_value_t newcaps[] = { CAP_NET_ADMIN, CAP_DAC_OVERRIDE, CAP_SYS_ADMIN };
    cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
    cap_set_proc(caps);

    printf("Capabilities after update: %s\n", cap_to_text(caps, NULL));
    cap_free(caps);

    system("cat /proc/self/status | grep Cap");
    ipv4_echo2();
    return 0;
}

核心问题:system()函数创建的子进程无法继承父进程设置的Capabilities,导致修改/proc/sys/net/ipv4/conf/acl_log_all/forwarding时出现权限问题。

解决方案

方法1:直接在进程内完成文件写入(推荐)

system()会启动shell,而shell默认会丢弃继承的Capabilities,最可靠的方式是跳过shell调用,直接用C标准函数完成写入操作,全程在同一个进程内执行,无需依赖Capabilities继承:

修改ipv4_echo2函数如下:

int ipv4_echo2() {
    const char *filepath = "/proc/sys/net/ipv4/conf/acl_log_all/forwarding";
    int fd = open(filepath, O_WRONLY);
    if (fd == -1) {
        printf("Failed to open %s: %s (errno: %d)\n", filepath, strerror(errno), errno);
        return 1;
    }
    const char *content = "1\n";
    ssize_t bytes_written = write(fd, content, strlen(content));
    if (bytes_written == -1) {
        printf("Failed to write to %s: %s (errno: %d)\n", filepath, strerror(errno), errno);
        close(fd);
        return 1;
    }
    printf("Successfully set %s to 1\n", filepath);
    close(fd);
    return 0;
}

方法2:让shell保留权限(不推荐,有安全风险)

如果必须使用system(),可以通过shell参数或给bash加Capabilities实现,但会扩大权限范围,仅适合测试场景:

  1. 调用system()时使用bash -p参数(保留有效UID/GID对应的权限):
snprintf(buf, sizeof(buf), "bash -p -c 'echo 1 > %s'", filepath);
  1. 或者给bash添加对应Capabilities(生产环境绝对禁用):
sudo setcap cap_net_admin,cap_dac_override,cap_sys_admin=eip /bin/bash

方法3:用exec系列函数替代system()

exec系列函数直接执行指定程序,不启动shell,能确保子进程继承父进程的Capabilities(前提是父进程Inheritable Capabilities设置正确):

修改ipv4_echo2函数如下:

int ipv4_echo2() {
    const char *filepath = "/proc/sys/net/ipv4/conf/acl_log_all/forwarding";
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork failed");
        return 1;
    }
    if (pid == 0) {
        // 子进程中重定向stdout到目标文件
        int fd = open(filepath, O_WRONLY);
        if (fd == -1) {
            perror("open failed");
            exit(1);
        }
        dup2(fd, STDOUT_FILENO);
        close(fd);
        // 执行echo命令
        execlp("echo", "echo", "1", NULL);
        // execlp返回则说明执行失败
        perror("execlp failed");
        exit(1);
    } else {
        // 父进程等待子进程执行完成
        int status;
        waitpid(pid, &status, 0);
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
            printf("Successfully set %s to 1\n", filepath);
            return 0;
        } else {
            printf("Failed to set %s\n", filepath);
            return 1;
        }
    }
}

内容的提问来源于stack exchange,提问作者Suresh Nayak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 13:07:38