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

如何让子进程仅拥有CAP_DAC_OVERRIDE能力?cap_set_flag设置失效求助

问题根源与解决办法

问题出在哪?

用sudo启动的父进程自带完整的CAP_PERMITTED能力集。如果只清了CAP_EFFECTIVE和CAP_INHERITABLE,没限制CAP_PERMITTED,或者修改能力后没调用cap_set_proc()让变更生效,子进程exec时会直接继承父进程的全量CAP_PERMITTED,导致能力没被限制住。另外,CAP_INHERITABLE没配置对的话,子进程也没法正确拿到指定能力。

正确实现流程

  1. 调用cap_get_proc()获取当前进程的能力状态。
  2. 用cap_set_flag配合CAP_CLEAR,把CAP_PERMITTED、CAP_EFFECTIVE、CAP_INHERITABLE三个集合的所有能力清掉。
  3. 把CAP_DAC_OVERRIDE分别添加到这三个集合里:CAP_PERMITTED是进程能拥有的能力上限,CAP_EFFECTIVE让能力立刻生效,CAP_INHERITABLE允许子进程继承这个能力。
  4. 调用cap_set_proc()把修改后的能力集应用到当前进程——这步绝对不能漏,不然之前的修改都是白做。
  5. 再fork+exec启动子进程,此时子进程就只会继承到CAP_DAC_OVERRIDE了。

修正后的主程序代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/capability.h>
#include <sys/wait.h>

int main() {
    cap_t caps = cap_get_proc();
    if (!caps) {
        perror("cap_get_proc failed");
        exit(EXIT_FAILURE);
    }

    // 清空所有能力集
    cap_value_t dac_cap = CAP_DAC_OVERRIDE;
    if (cap_set_flag(caps, CAP_PERMITTED, 1, &dac_cap, CAP_CLEAR) != 0 ||
        cap_set_flag(caps, CAP_EFFECTIVE, 1, &dac_cap, CAP_CLEAR) != 0 ||
        cap_set_flag(caps, CAP_INHERITABLE, 1, &dac_cap, CAP_CLEAR) != 0) {
        perror("cap_set_flag clear failed");
        cap_free(caps);
        exit(EXIT_FAILURE);
    }

    // 仅保留CAP_DAC_OVERRIDE
    if (cap_set_flag(caps, CAP_PERMITTED, 1, &dac_cap, CAP_SET) != 0 ||
        cap_set_flag(caps, CAP_EFFECTIVE, 1, &dac_cap, CAP_SET) != 0 ||
        cap_set_flag(caps, CAP_INHERITABLE, 1, &dac_cap, CAP_SET) != 0) {
        perror("cap_set_flag set failed");
        cap_free(caps);
        exit(EXIT_FAILURE);
    }

    // 应用能力修改,这步是关键!
    if (cap_set_proc(caps) != 0) {
        perror("cap_set_proc failed");
        cap_free(caps);
        exit(EXIT_FAILURE);
    }
    cap_free(caps);

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        execl("./test_cap", "test_cap", NULL);
        perror("execl failed");
        exit(EXIT_FAILURE);
    } else {
        wait(NULL);
    }

    return 0;
}

测试程序(test_cap.c)

#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>

int main() {
    cap_t caps = cap_get_proc();
    if (!caps) {
        perror("cap_get_proc failed");
        exit(EXIT_FAILURE);
    }

    char* cap_str = cap_to_text(caps, NULL);
    if (!cap_str) {
        perror("cap_to_text failed");
        cap_free(caps);
        exit(EXIT_FAILURE);
    }

    printf("子进程能力: %s\n", cap_str);
    cap_free(cap_str);
    cap_free(caps);

    return 0;
}

编译运行命令

# 编译时必须链接libcap库
gcc -o main main.c -lcap
gcc -o test_cap test_cap.c -lcap

# sudo运行主程序
sudo ./main

重点提醒

  • 别忘调用cap_set_proc():修改能力结构体后,只有这个函数能把变更同步到进程本身,不然子进程会继承原来的全能力。
  • 三个能力集都要改:缺了任何一个都可能导致能力没被正确限制或继承。
  • 编译加-lcap:否则会出现undefined reference错误,因为cap相关函数在libcap库里。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:05:21