Linux Capabilities机制不直接过滤系统调用,而是通过权限检查决定是否放行——当进程缺少对应capability(如CAP_NET_BIND_SERVICE)时,bind()等调用将因权限不足返回EPERM,从而实现按需阻断。

Linux Capabilities 本身不直接“过滤系统调用”,而是决定内核是否放行某次系统调用——它是一种权限检查机制,不是拦截或钩子工具。所谓“过滤”,实质是通过控制 capability 集合,让特定系统调用在权限不足时直接失败(返回 EACCES 或 EPERM),从而达到按需阻断的效果。
明确哪些系统调用依赖哪个 capability
每个特权系统调用背后都绑定一个或多个 capability。不查清依赖关系就盲目赋权,等于开盲盒。关键要对照内核文档和实际行为判断:
-
CAP_NET_BIND_SERVICE →
bind()绑定端口 -
CAP_NET_RAW →
socket(AF_PACKET, SOCK_RAW, ...)、ping、tcpdump底层抓包 -
CAP_SYS_TIME →
clock_settime()、settimeofday() -
CAP_SYS_ADMIN → 覆盖极广:挂载/卸载文件系统、修改
/proc/sys/参数、加载内核模块、使用bpf()等 -
CAP_SYS_PTRACE →
ptrace(PTRACE_ATTACH)、gdb、strace调试其他进程
用 setcap 精准绑定能力到二进制文件
这是最稳定、可审计、符合最小权限原则的方式。能力写入文件扩展属性,exec 时自动加载到新线程的能力集合中:
- 让普通用户运行的 Nginx 监听 80 端口:
sudo setcap cap_net_bind_service=+ep /usr/sbin/nginx - 允许非 root 用户执行
ping:sudo setcap cap_net_raw+ep /bin/ping - 同时赋予两个能力:
sudo setcap cap_sys_time,cap_sys_nice=+ep /usr/local/bin/timer-tool - 查看设置结果:
getcap /usr/sbin/nginx(输出应含= cap_net_bind_service+ep) - 清除所有能力:
sudo setcap -r /usr/sbin/nginx
注意:setcap 对 shell 脚本无效(内核只检查解释器本身的能力),也不作用于 noexec 挂载点上的文件。
运行时动态降权,避免全程持权
程序启动后若仍持有过多能力,攻击者可能利用漏洞长期维持高权。应在完成特权操作后立即丢弃:
- C 语言中调用
cap_clear()清空 effective 集,或用prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN)从 bounding set 中移除 - 命令行快速测试:
capsh --drop=cap_sys_admin -- -c "cat /proc/sys/kernel/pid_max"(该读取会失败) - 启动受限 shell:
capsh --inh=cap_net_raw --caps="cap_net_raw+eip" -- -c "/bin/bash",此时 bash 只能做 raw socket 相关操作
结合 bounding set 和 inheritable 实现父子隔离
bounding set 是所有能力的“总开关”,子进程无法获得父进程 bounding set 中不存在的能力。配合 inheritable 可实现安全的权限传递:
- 主程序以
capsh --bounding-set=-cap_sys_admin --inh=cap_net_admin -- -c ./master启动,其 bounding set 已剔除CAP_SYS_ADMIN - 子进程 exec 的网络工具必须自身有
cap_net_admin=i,且父进程 inheritable 集含该能力,子进程 permitted 才会继承 - 容器场景下,Docker 默认 drop 多数 capability,可用
--cap-add=net_admin显式开启,但禁止--cap-add=all
不复杂但容易忽略











