如何让子进程仅拥有CAP_DAC_OVERRIDE能力?cap_set_flag设置失效求助
问题根源与解决办法
问题出在哪?
用sudo启动的父进程自带完整的CAP_PERMITTED能力集。如果只清了CAP_EFFECTIVE和CAP_INHERITABLE,没限制CAP_PERMITTED,或者修改能力后没调用cap_set_proc()让变更生效,子进程exec时会直接继承父进程的全量CAP_PERMITTED,导致能力没被限制住。另外,CAP_INHERITABLE没配置对的话,子进程也没法正确拿到指定能力。
正确实现流程
- 调用
cap_get_proc()获取当前进程的能力状态。 - 用
cap_set_flag配合CAP_CLEAR,把CAP_PERMITTED、CAP_EFFECTIVE、CAP_INHERITABLE三个集合的所有能力清掉。 - 把
CAP_DAC_OVERRIDE分别添加到这三个集合里:CAP_PERMITTED是进程能拥有的能力上限,CAP_EFFECTIVE让能力立刻生效,CAP_INHERITABLE允许子进程继承这个能力。 - 调用
cap_set_proc()把修改后的能力集应用到当前进程——这步绝对不能漏,不然之前的修改都是白做。 - 再
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
相关产品推荐
相关产品推荐

